Version 2.8.0-dev.2.0
Merge commit 'd1e11f088108b5ec90fcc2faef7ed1437b018f47' into dev
diff --git a/DEPS b/DEPS
index f4b02a2..7b089e9 100644
--- a/DEPS
+++ b/DEPS
@@ -39,7 +39,7 @@
# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
# hashes. It requires access to the dart-build-access group, which EngProd
# has.
- "co19_rev": "9e3512c90f9110353909a0da71a871e33324034e",
+ "co19_rev": "6d84d8db719f2076e0c2bbc41db9297e803ab445",
"co19_2_rev": "368bfa9e877a2df003547f64bb17e30596af10c7",
# As Flutter does, we use Fuchsia's GN and Clang toolchain. These revision
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 580aa15..7a8e5b1 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -8212,6 +8212,56 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+ templateValueForRequiredParameterNotProvidedError =
+ const Template<Message Function(String name)>(
+ messageTemplate:
+ r"""Required named parameter '#name' must be provided.""",
+ withArguments: _withArgumentsValueForRequiredParameterNotProvidedError);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+ codeValueForRequiredParameterNotProvidedError =
+ const Code<Message Function(String name)>(
+ "ValueForRequiredParameterNotProvidedError",
+ templateValueForRequiredParameterNotProvidedError,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsValueForRequiredParameterNotProvidedError(String name) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ return new Message(codeValueForRequiredParameterNotProvidedError,
+ message: """Required named parameter '${name}' must be provided.""",
+ arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+ templateValueForRequiredParameterNotProvidedWarning =
+ const Template<Message Function(String name)>(
+ messageTemplate: r"""Missing required named parameter '#name'.""",
+ withArguments:
+ _withArgumentsValueForRequiredParameterNotProvidedWarning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+ codeValueForRequiredParameterNotProvidedWarning =
+ const Code<Message Function(String name)>(
+ "ValueForRequiredParameterNotProvidedWarning",
+ templateValueForRequiredParameterNotProvidedWarning,
+ severity: Severity.warning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsValueForRequiredParameterNotProvidedWarning(String name) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ return new Message(codeValueForRequiredParameterNotProvidedWarning,
+ message: """Missing required named parameter '${name}'.""",
+ arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeVarAsTypeName = messageVarAsTypeName;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
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 b1faa3f..2f33dac 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -2350,6 +2350,11 @@
}
// At this point, `token` is beforeName.
+ // Recovery: Inserted ! after method name.
+ if (optional('!', next.next)) {
+ next = next.next;
+ }
+
next = next.next;
value = next.stringValue;
if (getOrSet != null ||
@@ -2411,7 +2416,7 @@
}
}
if (typeInfo == noType) {
- if (varFinalOrConst == null && lateToken == null) {
+ if (varFinalOrConst == null) {
reportRecoverableError(name, codes.messageMissingConstFinalVarOrType);
}
} else {
@@ -2520,6 +2525,11 @@
}
Token parseMethodTypeVar(Token name) {
+ if (optional('!', name.next)) {
+ // Recovery
+ name = name.next;
+ reportRecoverableErrorWithToken(name, codes.templateUnexpectedToken);
+ }
if (!optional('<', name.next)) {
return noTypeParamOrArg.parseVariables(name, this);
}
@@ -5180,8 +5190,20 @@
return token;
}
+ /// Calls handleNonNullAssertExpression when the token points to `!<`.
+ /// Returns the input token if it doesn't point to `!<`, or the next token
+ /// (ready for parsing by e.g. computeMethodTypeArguments) if it does.
+ Token parseBangBeforeTypeArguments(Token token) {
+ if (optional('!', token.next) && optional('<', token.next.next)) {
+ token = token.next;
+ listener.handleNonNullAssertExpression(token);
+ }
+ return token;
+ }
+
Token parseSend(Token token, IdentifierContext context) {
Token beginToken = token = ensureIdentifier(token, context);
+ token = parseBangBeforeTypeArguments(token);
TypeParamOrArgInfo typeArg = computeMethodTypeArguments(token);
if (typeArg != noTypeParamOrArg) {
token = typeArg.parseArguments(token, this);
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart b/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart
index d57f969..c9a083f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/annotated_code_helper.dart
@@ -12,6 +12,11 @@
final Pattern commentEnd = new RegExp(r'\*/\s*');
class Annotation {
+ /// The index of the (corresponding) annotation in the annotated code test, or
+ /// `null` if the annotation doesn't correspond to an annotation in the
+ /// annotated code.
+ final int index;
+
/// 1-based line number of the annotation.
final int lineNo;
@@ -30,13 +35,13 @@
/// The annotation end text.
final String suffix;
- Annotation(this.lineNo, this.columnNo, this.offset, this.prefix, this.text,
- this.suffix)
+ Annotation(this.index, this.lineNo, this.columnNo, this.offset, this.prefix,
+ this.text, this.suffix)
: assert(offset != null);
String toString() =>
- 'Annotation(lineNo=$lineNo,columnNo=$columnNo,offset=$offset,'
- 'prefix=$prefix,text=$text,suffix=$suffix)';
+ 'Annotation(index=$index,lineNo=$lineNo,columnNo=$columnNo,'
+ 'offset=$offset,prefix=$prefix,text=$text,suffix=$suffix)';
}
/// A source code text with annotated positions.
@@ -98,8 +103,8 @@
annotatedCode.substring(startMatch.start, startMatch.end);
String text = annotatedCode.substring(startMatch.end, endMatch.start);
String suffix = annotatedCode.substring(endMatch.start, endMatch.end);
- annotations.add(
- new Annotation(lineNo, columnNo, offset, prefix, text, suffix));
+ annotations.add(new Annotation(annotations.length, lineNo, columnNo,
+ offset, prefix, text, suffix));
index = endMatch.end;
continue;
}
@@ -171,8 +176,8 @@
int lineNo, int columnNo, String prefix, String text, String suffix) {
_ensureLineStarts();
int offset = _lineStarts[lineNo - 1] + (columnNo - 1);
- annotations
- .add(new Annotation(lineNo, columnNo, offset, prefix, text, suffix));
+ annotations.add(new Annotation(
+ annotations.length, lineNo, columnNo, offset, prefix, text, suffix));
}
int get lineCount {
@@ -213,7 +218,22 @@
String toText() {
StringBuffer sb = new StringBuffer();
List<Annotation> list = annotations.toList()
- ..sort((a, b) => a.offset.compareTo(b.offset));
+ ..sort((a, b) {
+ int result = a.offset.compareTo(b.offset);
+ if (result == 0) {
+ if (a.index != null && b.index != null) {
+ result = a.index.compareTo(b.index);
+ } else if (a.index != null) {
+ result = -1;
+ } else if (b.index != null) {
+ result = 1;
+ }
+ }
+ if (result == 0) {
+ result = annotations.indexOf(a).compareTo(annotations.indexOf(b));
+ }
+ return result;
+ });
int offset = 0;
for (Annotation annotation in list) {
sb.write(sourceCode.substring(offset, annotation.offset));
@@ -258,6 +278,7 @@
if (prefixSet.containsAll(markers)) {
for (String part in markers) {
Annotation subAnnotation = new Annotation(
+ annotation.index,
annotation.lineNo,
annotation.columnNo,
annotation.offset,
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart b/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart
index f722b52..6800762 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/id_generation.dart
@@ -11,14 +11,19 @@
Map<String, MemberAnnotations<IdValue>> expectedMaps,
Uri mainUri,
Map<String, Map<Uri, Map<Id, ActualData<T>>>> actualData,
- DataInterpreter<T> dataInterpreter) {
+ DataInterpreter<T> dataInterpreter,
+ {Annotation Function(Annotation expected, Annotation actual) createDiff}) {
Set<Uri> uriSet = {};
Set<String> actualMarkers = actualData.keys.toSet();
Map<Uri, Map<Id, Map<String, IdValue>>> idValuePerUri = {};
Map<Uri, Map<Id, Map<String, ActualData<T>>>> actualDataPerUri = {};
void addData(String marker, Uri uri, Map<Id, IdValue> data) {
- assert(uri != null);
+ if (uri == null) {
+ // TODO(johnniwinther): Avoid `null` URIs.
+ assert(data.isEmpty, "Non-empty data without uri: $data");
+ return;
+ }
uriSet.add(uri);
Map<Id, Map<String, IdValue>> idValuePerId = idValuePerUri[uri] ??= {};
data.forEach((Id id, IdValue value) {
@@ -37,7 +42,11 @@
actualData
.forEach((String marker, Map<Uri, Map<Id, ActualData<T>>> dataPerUri) {
dataPerUri.forEach((Uri uri, Map<Id, ActualData<T>> dataMap) {
- assert(uri != null);
+ if (uri == null) {
+ // TODO(johnniwinther): Avoid `null` URIs.
+ assert(dataMap.isEmpty, "Non-empty data for `null` uri: $dataMap");
+ return;
+ }
uriSet.add(uri);
dataMap.forEach((Id id, ActualData<T> data) {
Map<Id, Map<String, ActualData<T>>> actualDataPerId =
@@ -54,9 +63,12 @@
Map<Id, Map<String, IdValue>> idValuePerId = idValuePerUri[uri] ?? {};
Map<Id, Map<String, ActualData<T>>> actualDataPerId =
actualDataPerUri[uri] ?? {};
- result[uri] = _computeAnnotations(annotatedCode[uri], expectedMaps.keys,
- actualMarkers, idValuePerId, actualDataPerId, dataInterpreter,
- sortMarkers: false);
+ AnnotatedCode code = annotatedCode[uri];
+ assert(
+ code != null, "No annotated code for ${uri} in ${annotatedCode.keys}");
+ result[uri] = _computeAnnotations(code, expectedMaps.keys, actualMarkers,
+ idValuePerId, actualDataPerId, dataInterpreter,
+ sortMarkers: false, createDiff: createDiff);
}
return result;
}
@@ -70,7 +82,8 @@
DataInterpreter<T> dataInterpreter,
{String defaultPrefix: '/*',
String defaultSuffix: '*/',
- bool sortMarkers: true}) {
+ bool sortMarkers: true,
+ Annotation Function(Annotation expected, Annotation actual) createDiff}) {
assert(annotatedCode != null);
Annotation createAnnotationFromData(
@@ -117,6 +130,7 @@
}
return new Annotation(
+ annotation?.index,
annotation?.lineNo ?? -1,
annotation?.columnNo ?? -1,
offset,
@@ -136,27 +150,35 @@
for (String marker in supportedMarkers) {
IdValue idValue = idValuePerMarker[marker];
ActualData<T> actualData = actualDataPerMarker[marker];
+ Annotation expectedAnnotation;
+ Annotation actualAnnotation;
if (idValue != null && actualData != null) {
if (dataInterpreter.isAsExpected(actualData.value, idValue.value) ==
null) {
// Use existing annotation.
- newAnnotationsPerMarker[marker] = idValue.annotation;
+ expectedAnnotation = actualAnnotation = idValue.annotation;
} else {
- newAnnotationsPerMarker[marker] =
+ expectedAnnotation = idValue.annotation;
+ actualAnnotation =
createAnnotationFromData(actualData, idValue.annotation);
}
} else if (idValue != null && !actualMarkers.contains(marker)) {
// Use existing annotation if no actual data is provided for this
// marker.
- newAnnotationsPerMarker[marker] = idValue.annotation;
+ expectedAnnotation = actualAnnotation = idValue.annotation;
} else if (actualData != null) {
if (dataInterpreter.isAsExpected(actualData.value, null) != null) {
// Insert annotation if the actual value is not equivalent to an
// empty value.
- newAnnotationsPerMarker[marker] =
- createAnnotationFromData(actualData, null);
+ actualAnnotation = createAnnotationFromData(actualData, null);
}
}
+ Annotation annotation = createDiff != null
+ ? createDiff(expectedAnnotation, actualAnnotation)
+ : actualAnnotation;
+ if (annotation != null) {
+ newAnnotationsPerMarker[marker] = annotation;
+ }
}
Map<String, Map<String, Annotation>> groupedByText = {};
@@ -180,6 +202,7 @@
}
Annotation firstAnnotation = annotations.values.first;
result.add(new Annotation(
+ firstAnnotation.index,
firstAnnotation.lineNo,
firstAnnotation.columnNo,
firstAnnotation.offset,
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
index b3e4d23..c9dbd67 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
@@ -110,6 +110,48 @@
return '${colorizeDelimiter(start)}$text${colorizeDelimiter(end)}';
}
+/// Creates an annotation that shows the difference between [expected] and
+/// [actual].
+Annotation createAnnotationsDiff(Annotation expected, Annotation actual) {
+ if (identical(expected, actual)) return null;
+ if (expected != null && actual != null) {
+ return new Annotation(
+ expected.index,
+ expected.lineNo,
+ expected.columnNo,
+ expected.offset,
+ expected.prefix,
+ '${colorizeExpected(expected.text)}'
+ '${colorizeDelimiter(' | ')}'
+ '${colorizeActual(actual.text)}',
+ expected.suffix);
+ } else if (expected != null) {
+ return new Annotation(
+ expected.index,
+ expected.lineNo,
+ expected.columnNo,
+ expected.offset,
+ expected.prefix,
+ '${colorizeExpected(expected.text)}'
+ '${colorizeDelimiter(' | ')}'
+ '${colorizeActual('---')}',
+ expected.suffix);
+ } else if (actual != null) {
+ return new Annotation(
+ actual.index,
+ actual.lineNo,
+ actual.columnNo,
+ actual.offset,
+ actual.prefix,
+ '${colorizeExpected('---')}'
+ '${colorizeDelimiter(' | ')}'
+ '${colorizeActual(actual.text)}',
+ actual.suffix);
+ } else {
+ return null;
+ }
+}
+
/// Encapsulates the member data computed for each source file of interest.
/// It's a glorified wrapper around a map of maps, but written this way to
/// provide a little more information about what it's doing. [DataType] refers
@@ -442,72 +484,6 @@
return sb.toString();
}
-/// Computed and expected data for an annotated test. This is used for checking
-/// and displaying results of an annotated test.
-class IdData<T> {
- final Map<Uri, AnnotatedCode> code;
- final MemberAnnotations<IdValue> expectedMaps;
- final CompiledData<T> _compiledData;
- final MemberAnnotations<ActualData<T>> _actualMaps = new MemberAnnotations();
-
- IdData(this.code, this.expectedMaps, this._compiledData) {
- for (Uri uri in code.keys) {
- _actualMaps[uri] = _compiledData.actualMaps[uri] ?? <Id, ActualData<T>>{};
- }
- _actualMaps.globalData.addAll(_compiledData.globalData);
- }
-
- Uri get mainUri => _compiledData.mainUri;
- MemberAnnotations<ActualData<T>> get actualMaps => _actualMaps;
-
- String actualCode(Uri uri) {
- Map<int, List<String>> annotations = <int, List<String>>{};
- actualMaps[uri].forEach((Id id, ActualData<T> data) {
- annotations.putIfAbsent(data.offset, () => []).add('${data.value}');
- });
- return withAnnotations(code[uri].sourceCode, annotations);
- }
-
- String diffCode(Uri uri, DataInterpreter<T> dataValidator) {
- Map<int, List<String>> annotations = <int, List<String>>{};
- actualMaps[uri].forEach((Id id, ActualData<T> data) {
- IdValue expectedValue = expectedMaps[uri][id];
- T actualValue = data.value;
- String unexpectedMessage =
- dataValidator.isAsExpected(actualValue, expectedValue?.value);
- if (unexpectedMessage != null) {
- String expected = expectedValue?.toString() ?? '';
- String actual = dataValidator.getText(actualValue);
- int offset = getOffsetFromId(id, uri);
- if (offset != null) {
- String value1 = '${expected}';
- String value2 = IdValue.idToString(id, '${actual}');
- annotations
- .putIfAbsent(offset, () => [])
- .add(colorizeDiff(value1, ' | ', value2));
- }
- }
- });
- expectedMaps[uri].forEach((Id id, IdValue expected) {
- if (!actualMaps[uri].containsKey(id)) {
- int offset = getOffsetFromId(id, uri);
- if (offset != null) {
- String value1 = '${expected}';
- String value2 = '---';
- annotations
- .putIfAbsent(offset, () => [])
- .add(colorizeDiff(value1, ' | ', value2));
- }
- }
- });
- return withAnnotations(code[uri].sourceCode, annotations);
- }
-
- int getOffsetFromId(Id id, Uri uri) {
- return _compiledData.getOffsetFromId(id, uri);
- }
-}
-
/// Checks [compiledData] against the expected data in [expectedMaps] derived
/// from [code].
Future<TestResult<T>> checkCode<T>(
@@ -521,15 +497,15 @@
bool fatalErrors: true,
bool succinct: false,
void onFailure(String message)}) async {
- IdData<T> data = new IdData<T>(code, expectedMaps, compiledData);
bool hasFailure = false;
Set<Uri> neededDiffs = new Set<Uri>();
void checkActualMap(
Map<Id, ActualData<T>> actualMap, Map<Id, IdValue> expectedMap,
[Uri uri]) {
+ expectedMap ??= {};
bool hasLocalFailure = false;
- actualMap.forEach((Id id, ActualData<T> actualData) {
+ actualMap?.forEach((Id id, ActualData<T> actualData) {
T actual = actualData.value;
String actualText = dataInterpreter.getText(actual);
@@ -582,16 +558,17 @@
}
}
- data.actualMaps.forEach((Uri uri, Map<Id, ActualData<T>> actualMap) {
- checkActualMap(actualMap, data.expectedMaps[uri], uri);
+ compiledData.actualMaps.forEach((Uri uri, Map<Id, ActualData<T>> actualMap) {
+ checkActualMap(actualMap, expectedMaps[uri], uri);
});
- checkActualMap(data.actualMaps.globalData, data.expectedMaps.globalData);
+ checkActualMap(compiledData.globalData, expectedMaps.globalData);
Set<Id> missingIds = new Set<Id>();
void checkMissing(
Map<Id, IdValue> expectedMap, Map<Id, ActualData<T>> actualMap,
[Uri uri]) {
- expectedMap.forEach((Id id, IdValue expected) {
+ actualMap ??= {};
+ expectedMap?.forEach((Id id, IdValue expected) {
if (!actualMap.containsKey(id)) {
missingIds.add(id);
String message = 'MISSING $modeName DATA for ${id.descriptor}: '
@@ -610,15 +587,27 @@
}
}
- data.expectedMaps.forEach((Uri uri, Map<Id, IdValue> expectedMap) {
- checkMissing(expectedMap, data.actualMaps[uri], uri);
+ expectedMaps.forEach((Uri uri, Map<Id, IdValue> expectedMap) {
+ checkMissing(expectedMap, compiledData.actualMaps[uri], uri);
});
- checkMissing(data.expectedMaps.globalData, data.actualMaps.globalData);
+ checkMissing(expectedMaps.globalData, compiledData.globalData);
if (!succinct) {
- for (Uri uri in neededDiffs) {
- print('--annotations diff [${uri.pathSegments.last}]-------------');
- print(data.diffCode(uri, dataInterpreter));
- print('----------------------------------------------------------');
+ if (neededDiffs.isNotEmpty) {
+ Map<Uri, List<Annotation>> annotations = computeAnnotationsPerUri(
+ code,
+ {'dummyMarker': expectedMaps},
+ compiledData.mainUri,
+ {'dummyMarker': compiledData.actualMaps},
+ dataInterpreter,
+ createDiff: createAnnotationsDiff);
+ for (Uri uri in neededDiffs) {
+ print('--annotations diff [${uri.pathSegments.last}]-------------');
+ AnnotatedCode annotatedCode = code[uri];
+ print(new AnnotatedCode(annotatedCode.annotatedCode,
+ annotatedCode.sourceCode, annotations[uri])
+ .toText());
+ print('----------------------------------------------------------');
+ }
}
}
if (missingIds.isNotEmpty) {
diff --git a/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart b/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart
index a36a670..deafff8 100644
--- a/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart
+++ b/pkg/_fe_analyzer_shared/test/annotated_code_helper_test.dart
@@ -8,23 +8,19 @@
import 'package:_fe_analyzer_shared/src/testing/id_generation.dart';
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
-main() async {
- await testDir('pkg/_fe_analyzer_shared/test/constants/data', sharedMarkers);
- await testDir(
- 'pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data',
+main() {
+ testDir('pkg/_fe_analyzer_shared/test/constants/data', sharedMarkers);
+ testDir('pkg/_fe_analyzer_shared/test/flow_analysis/assigned_variables/data',
cfeAnalyzerMarkers);
- await testDir(
- 'pkg/_fe_analyzer_shared/test/flow_analysis/definite_assignment/data',
+ testDir('pkg/_fe_analyzer_shared/test/flow_analysis/definite_assignment/data',
cfeAnalyzerMarkers);
- await testDir('pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data',
+ testDir('pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data',
cfeAnalyzerMarkers);
- await testDir('pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data',
+ testDir('pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data',
cfeAnalyzerMarkers);
- await testDir(
- 'pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data',
+ testDir('pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data',
cfeAnalyzerMarkers);
- await testDir(
- 'pkg/_fe_analyzer_shared/test/inheritance/data', cfeAnalyzerMarkers);
+ testDir('pkg/_fe_analyzer_shared/test/inheritance/data', cfeAnalyzerMarkers);
}
void expectStringEquals(String value1, String value2) {
@@ -33,7 +29,7 @@
}
}
-Future<void> testDir(String dataDirPath, List<String> supportedMarkers) {
+void testDir(String dataDirPath, List<String> supportedMarkers) {
Directory dataDir = Directory(dataDirPath);
String relativeDir = dataDir.uri.path.replaceAll(Uri.base.path, '');
print('Data dir: ${relativeDir}');
diff --git a/pkg/_fe_analyzer_shared/test/id_generation_test.dart b/pkg/_fe_analyzer_shared/test/id_generation_test.dart
index bc772d7..6010ed5 100644
--- a/pkg/_fe_analyzer_shared/test/id_generation_test.dart
+++ b/pkg/_fe_analyzer_shared/test/id_generation_test.dart
@@ -31,10 +31,8 @@
some code/*test*/some more code
''');
testString('/*a.test1*//*b.test2*//*c.test3*/');
- testString('/*b.test2*//*a.test1*//*c.test3*/',
- expectedResult: '/*a.test1*//*b.test2*//*c.test3*/');
- testString('/*a.test1*//*c.test3*//*b.test2*/',
- expectedResult: '/*a.test1*//*b.test2*//*c.test3*/');
+ testString('/*b.test2*//*a.test1*//*c.test3*/');
+ testString('/*a.test1*//*c.test3*//*b.test2*/');
testString('some code',
actualData: {
diff --git a/pkg/analysis_server/analysis_options.yaml b/pkg/analysis_server/analysis_options.yaml
index 3fbb3af..f20b958 100644
--- a/pkg/analysis_server/analysis_options.yaml
+++ b/pkg/analysis_server/analysis_options.yaml
@@ -12,7 +12,6 @@
# Ignoring "style" lint rules from pedantic for now. There are pre-existing
# violations that need to be cleaned up. Each one can be cleaned up and
# enabled according to the value provided.
- avoid_init_to_null: ignore
avoid_return_types_on_setters: ignore
empty_catches: ignore
prefer_contains: ignore
@@ -38,9 +37,9 @@
- camel_case_extensions
#- omit_local_variable_types # 8650
- prefer_adjacent_string_concatenation
- #- prefer_collection_literals # 130
+ - prefer_collection_literals
- prefer_conditional_assignment
- #- prefer_final_fields # 35
+ - prefer_final_fields
- prefer_for_elements_to_map_fromIterable
- prefer_generic_function_type_aliases
#- prefer_if_null_operators # 22
diff --git a/pkg/analysis_server/benchmark/benchmarks.dart b/pkg/analysis_server/benchmark/benchmarks.dart
index c477bdc..e20e28a 100644
--- a/pkg/analysis_server/benchmark/benchmarks.dart
+++ b/pkg/analysis_server/benchmark/benchmarks.dart
@@ -219,7 +219,7 @@
CompoundBenchMarkResult combined = CompoundBenchMarkResult(name);
List<String> keys =
- (Set<String>()..addAll(results.keys)..addAll(o.results.keys)).toList();
+ (<String>{}..addAll(results.keys)..addAll(o.results.keys)).toList();
for (String key in keys) {
combined.add(key, _combine(results[key], o.results[key]));
diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
index 29366ea..6787fb8 100644
--- a/pkg/analysis_server/benchmark/integration/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -153,7 +153,7 @@
class Measurement {
final String tag;
final bool notification;
- final List<Duration> elapsedTimes = List<Duration>();
+ final List<Duration> elapsedTimes = <Duration>[];
int errorCount = 0;
int unexpectedResultCount = 0;
@@ -223,7 +223,7 @@
* while running the analysis server
*/
class Results {
- Map<String, Measurement> measurements = Map<String, Measurement>();
+ Map<String, Measurement> measurements = <String, Measurement>{};
/**
* Display results on stdout.
diff --git a/pkg/analysis_server/benchmark/integration/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
index 60b8651..0368037 100644
--- a/pkg/analysis_server/benchmark/integration/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -23,7 +23,7 @@
abstract class CommonInputConverter extends Converter<String, Operation> {
static final ERROR_PREFIX = 'Server responded with an error: ';
final Logger logger = Logger('InstrumentationInputConverter');
- final Set<String> eventsSeen = Set<String>();
+ final Set<String> eventsSeen = <String>{};
/**
* A mapping from request/response id to request json
@@ -256,7 +256,7 @@
return result;
}
if (json is Map) {
- Map<String, dynamic> result = Map<String, dynamic>();
+ Map<String, dynamic> result = <String, dynamic>{};
json.forEach((origKey, value) {
result[translateSrcPaths(origKey)] = translateSrcPaths(value);
});
diff --git a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
index 9dfd1eb..588b3fc 100644
--- a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
@@ -18,14 +18,14 @@
* into a series of operations to be sent to the analysis server.
*/
class InstrumentationInputConverter extends CommonInputConverter {
- final Set<String> codesSeen = Set<String>();
+ final Set<String> codesSeen = <String>{};
/**
* [readBuffer] holds the contents of the file being read from disk
* as recorded in the instrumentation log
* or `null` if not converting a "Read" entry.
*/
- StringBuffer readBuffer = null;
+ StringBuffer readBuffer;
InstrumentationInputConverter(String tmpSrcDirPath, PathMap srcPathMap)
: super(tmpSrcDirPath, srcPathMap);
@@ -106,7 +106,7 @@
* Extract fields from the given [line].
*/
static List<String> _parseFields(String line) {
- List<String> fields = List<String>();
+ List<String> fields = <String>[];
int index = 0;
StringBuffer sb = StringBuffer();
while (index < line.length) {
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 8758c49..d01715f 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -169,7 +169,7 @@
this.instrumentationService, {
this.requestStatistics,
DiagnosticServer diagnosticServer,
- this.detachableFileSystemManager = null,
+ this.detachableFileSystemManager,
}) : super(options, diagnosticServer, baseResourceProvider) {
notificationManager = NotificationManager(channel, resourceProvider);
@@ -905,8 +905,8 @@
@override
ContextBuilder createContextBuilder(Folder folder, AnalysisOptions options) {
- String defaultPackageFilePath = null;
- String defaultPackagesDirectoryPath = null;
+ String defaultPackageFilePath;
+ String defaultPackagesDirectoryPath;
String path = (analysisServer.contextManager as ContextManagerImpl)
.normalizedPackageRoots[folder.path];
if (path != null) {
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index dac52410..7f38fad 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -72,7 +72,7 @@
final ServerPerformance performanceDuringStartup = ServerPerformance();
/// The set of the files that are currently priority.
- final Set<String> priorityFiles = Set<String>();
+ final Set<String> priorityFiles = <String>{};
final List<String> analyzableFilePatterns = <String>[
'**/*.${AnalysisEngine.SUFFIX_DART}',
@@ -92,7 +92,7 @@
/// A list of the globs used to determine which files should be analyzed. The
/// list is lazily created and should be accessed using [analyzedFilesGlobs].
- List<Glob> _analyzedFilesGlobs = null;
+ List<Glob> _analyzedFilesGlobs;
AbstractAnalysisServer(this.options, this.diagnosticServer,
ResourceProvider baseResourceProvider)
diff --git a/pkg/analysis_server/lib/src/computer/computer_closingLabels.dart b/pkg/analysis_server/lib/src/computer/computer_closingLabels.dart
index a7577cd..c4b28bf 100644
--- a/pkg/analysis_server/lib/src/computer/computer_closingLabels.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_closingLabels.dart
@@ -15,8 +15,8 @@
final LineInfo _lineInfo;
final CompilationUnit _unit;
final List<ClosingLabel> _closingLabels = [];
- final Set<ClosingLabel> hasNestingSet = Set();
- final Set<ClosingLabel> isSingleLineSet = Set();
+ final Set<ClosingLabel> hasNestingSet = {};
+ final Set<ClosingLabel> isSingleLineSet = {};
DartUnitClosingLabelsComputer(this._lineInfo, this._unit);
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 4a1c9b1..7d04309 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -33,7 +33,7 @@
while (token != null && token.type != TokenType.EOF) {
Token commentToken = token.precedingComments;
while (commentToken != null) {
- HighlightRegionType highlightType = null;
+ HighlightRegionType highlightType;
if (commentToken.type == TokenType.MULTI_LINE_COMMENT) {
if (commentToken.lexeme.startsWith('/**')) {
highlightType = HighlightRegionType.COMMENT_DOCUMENTATION;
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
index 11b1bf2..25c43d0 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
@@ -33,7 +33,7 @@
while (token != null && token.type != TokenType.EOF) {
Token commentToken = token.precedingComments;
while (commentToken != null) {
- HighlightRegionType highlightType = null;
+ HighlightRegionType highlightType;
if (commentToken.type == TokenType.MULTI_LINE_COMMENT) {
if (commentToken.lexeme.startsWith('/**')) {
highlightType = HighlightRegionType.COMMENT_DOCUMENTATION;
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 2689de5..b955006 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -24,6 +24,10 @@
DartUnitHoverComputer(this._dartdocInfo, this._unit, this._offset);
+ bool get _isNonNullableByDefault {
+ return _unit.declaredElement.library.isNonNullableByDefault;
+ }
+
/**
* Returns the computed hover, maybe `null`.
*/
@@ -63,7 +67,7 @@
}
}
// description
- hover.elementDescription = element.toString();
+ hover.elementDescription = _elementDisplayString(element);
if (node is InstanceCreationExpression && node.keyword == null) {
String prefix = node.isConst ? '(const) ' : '(new) ';
hover.elementDescription = prefix + hover.elementDescription;
@@ -106,7 +110,9 @@
hover.dartdoc = computeDocumentation(_dartdocInfo, element);
}
// parameter
- hover.parameter = _safeToString(expression.staticParameterElement);
+ hover.parameter = _elementDisplayString(
+ expression.staticParameterElement,
+ );
// types
{
AstNode parent = expression.parent;
@@ -120,7 +126,7 @@
staticType = null;
}
}
- hover.staticType = _safeToString(staticType);
+ hover.staticType = _typeDisplayString(staticType);
}
// done
return hover;
@@ -129,6 +135,16 @@
return null;
}
+ String _elementDisplayString(Element element) {
+ return element?.getDisplayString(
+ withNullability: _isNonNullableByDefault,
+ );
+ }
+
+ String _typeDisplayString(DartType type) {
+ return type?.getDisplayString(withNullability: _isNonNullableByDefault);
+ }
+
static String computeDocumentation(
DartdocDirectiveInfo dartdocInfo, Element element) {
// TODO(dantup) We're reusing this in parameter information - move it
@@ -178,6 +194,4 @@
}
return node.staticType;
}
-
- static String _safeToString(obj) => obj?.toString();
}
diff --git a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
index f59e3de..48070f8 100644
--- a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
+++ b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
@@ -215,7 +215,7 @@
return false;
}
- ImportDirective preferredDirective = null;
+ ImportDirective preferredDirective;
int bestEditCount = -1;
bool deleteHide = false;
bool addShow = false;
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 473cf4b..1039196 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -4,7 +4,6 @@
import 'dart:async';
import 'dart:collection';
-import 'dart:convert';
import 'dart:core';
import 'package:analysis_server/src/plugin/notification_manager.dart';
@@ -14,6 +13,7 @@
import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/context/context_root.dart';
+import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -28,13 +28,9 @@
import 'package:analyzer/src/source/path_filter.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/util/glob.dart';
-import 'package:analyzer/src/util/uri.dart';
import 'package:analyzer/src/util/yaml.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
-import 'package:package_config/packages.dart';
-import 'package:package_config/packages_file.dart' as pkgfile show parse;
-import 'package:package_config/src/packages_impl.dart' show MapPackages;
import 'package:path/path.dart' as pathos;
import 'package:watcher/watcher.dart';
import 'package:yaml/yaml.dart';
@@ -120,7 +116,7 @@
* be watched for changes. I believe the use case for watching these files
* is no longer relevant.
*/
- Set<String> _dependencies = Set<String>();
+ Set<String> _dependencies = <String>{};
/**
* The analysis driver that was created for the [folder].
@@ -864,7 +860,7 @@
_isInTopLevelDocDir(info.folder.path, folder.path)) {
return;
}
- List<Resource> children = null;
+ List<Resource> children;
try {
children = folder.getChildren();
} on FileSystemException {
@@ -1062,7 +1058,7 @@
// TODO(paulberry): We shouldn't be using JavaFile here because it
// makes the code untestable (see dartbug.com/23909).
JavaFile packagesDirOrFile = JavaFile(packageRoot);
- Map<String, List<Folder>> packageMap = Map<String, List<Folder>>();
+ Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
if (packagesDirOrFile.isDirectory()) {
for (JavaFile file in packagesDirOrFile.listFiles()) {
// Ensure symlinks in packages directory are canonicalized
@@ -1083,7 +1079,10 @@
return PackageMapDisposition(packageMap, packageRoot: packageRoot);
} else if (packagesDirOrFile.isFile()) {
File packageSpecFile = resourceProvider.getFile(packageRoot);
- Packages packages = _readPackagespec(packageSpecFile);
+ Packages packages = parseDotPackagesFile(
+ resourceProvider,
+ packageSpecFile,
+ );
if (packages != null) {
return PackagesFileDisposition(packages);
}
@@ -1097,7 +1096,10 @@
} else {
// Try .packages first.
if (pathContext.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
- Packages packages = _readPackagespec(packagespecFile);
+ Packages packages = parseDotPackagesFile(
+ resourceProvider,
+ packagespecFile,
+ );
return PackagesFileDisposition(packages);
}
@@ -1118,9 +1120,13 @@
* file for code being analyzed using the given [packages].
*/
AnalysisOptionsProvider _createAnalysisOptionsProvider(Packages packages) {
- Map<String, List<Folder>> packageMap =
- ContextBuilder(resourceProvider, null, null)
- .convertPackagesToMap(packages);
+ var packageMap = <String, List<Folder>>{};
+ if (packages != null) {
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
+ }
+
List<UriResolver> resolvers = <UriResolver>[
ResourceUriResolver(resourceProvider),
PackageMapUriResolver(resourceProvider, packageMap),
@@ -1340,7 +1346,7 @@
///
/// Returns null if there are no embedded/configured options.
YamlMap _getEmbeddedOptions(ContextInfo info) {
- Map embeddedOptions = null;
+ Map embeddedOptions;
EmbedderYamlLocator locator =
info.disposition.getEmbedderLocator(resourceProvider);
Iterable<YamlMap> maps = locator.embedderYamls.values;
@@ -1609,18 +1615,6 @@
return resourceProvider.getFile(path).readAsStringSync();
}
- Packages _readPackagespec(File specFile) {
- try {
- String contents = specFile.readAsStringSync();
- Map<String, Uri> map =
- pkgfile.parse(utf8.encode(contents), Uri.file(specFile.path));
- return MapPackages(map);
- } catch (_) {
- //TODO(pquitslund): consider creating an error for the spec file.
- return null;
- }
- }
-
/**
* Recompute the [FolderDisposition] for the context described by [info],
* and update the client appropriately.
@@ -1812,13 +1806,9 @@
if (packageMap == null) {
packageMap = <String, List<Folder>>{};
if (packages != null) {
- var pathContext = resourceProvider.pathContext;
- packages.asMap().forEach((String name, Uri uri) {
- if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) {
- String path = fileUriToNormalizedPath(pathContext, uri);
- packageMap[name] = <Folder>[resourceProvider.getFolder(path)];
- }
- });
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
}
}
return packageMap;
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 645c82d..0891227 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -484,7 +484,7 @@
// options
var params = AnalysisUpdateOptionsParams.fromRequest(request);
AnalysisOptions newOptions = params.options;
- List<OptionUpdater> updaters = List<OptionUpdater>();
+ List<OptionUpdater> updaters = <OptionUpdater>[];
if (newOptions.generateDart2jsHints != null) {
updaters.add((engine.AnalysisOptionsImpl options) {
options.dart2jsHint = newOptions.generateDart2jsHints;
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 547dd94..96d3a52 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -41,7 +41,7 @@
/**
* The completion services that the client is currently subscribed.
*/
- final Set<CompletionService> subscriptions = Set<CompletionService>();
+ final Set<CompletionService> subscriptions = <CompletionService>{};
/**
* The next completion response id.
@@ -354,8 +354,8 @@
Set<String> includedElementNames;
List<IncludedSuggestionRelevanceTag> includedSuggestionRelevanceTags;
if (subscriptions.contains(CompletionService.AVAILABLE_SUGGESTION_SETS)) {
- includedElementKinds = Set<ElementKind>();
- includedElementNames = Set<String>();
+ includedElementKinds = <ElementKind>{};
+ includedElementNames = <String>{};
includedSuggestionRelevanceTags = <IncludedSuggestionRelevanceTag>[];
}
diff --git a/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart b/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart
index e059c7f..8b4cd5d 100644
--- a/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart
+++ b/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart
@@ -299,7 +299,7 @@
/// When the completion domain subscribes for changes, we start redirecting
/// changes to this listener.
- void Function(LibraryChange) _listener = null;
+ void Function(LibraryChange) _listener;
DeclarationsTrackerData(this._tracker) {
_tracker.changes.listen((change) {
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 9b3da69..d75faef 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -270,7 +270,7 @@
//
// Compute fixes associated with server-generated errors.
//
- List<AnalysisErrorFixes> errorFixesList = null;
+ List<AnalysisErrorFixes> errorFixesList;
while (errorFixesList == null) {
try {
errorFixesList = await _computeServerErrorFixes(request, file, offset);
diff --git a/pkg/analysis_server/lib/src/edit/fix/dartfix_info.dart b/pkg/analysis_server/lib/src/edit/fix/dartfix_info.dart
index 25cb287..c66bee3 100644
--- a/pkg/analysis_server/lib/src/edit/fix/dartfix_info.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/dartfix_info.dart
@@ -72,6 +72,7 @@
LintFixInfo.nullClosures,
LintFixInfo.omitLocalVariableTypes,
LintFixInfo.preferAdjacentStringConcatenation,
+ LintFixInfo.preferCollectionLiterals,
LintFixInfo.preferConditionalAssignment,
LintFixInfo.preferEqualForDefaultValues,
LintFixInfo.preferFinalFields,
@@ -80,6 +81,7 @@
LintFixInfo.preferIfNullOperators,
LintFixInfo.preferIsEmpty,
LintFixInfo.preferIsNotEmpty,
+ LintFixInfo.preferIterableWhereType,
LintFixInfo.preferSingleQuotes,
LintFixInfo.preferSpreadCollections,
LintFixInfo.slashForDocComments,
@@ -88,6 +90,7 @@
LintFixInfo.unnecessaryConst,
LintFixInfo.unnecessaryNew,
LintFixInfo.unnecessaryThis,
+ LintFixInfo.useFunctionTypeSyntaxForParameters,
LintFixInfo.useRethrowWhenPossible,
//
// Other fixes
@@ -215,13 +218,9 @@
// avoid_types_as_parameter_names
// camel_case_extensions
// library_names
- // prefer_collection_literals
// prefer_contains
- // prefer_iterable_whereType
// recursive_getters
- // unnecessary_null_in_if_null_operators
// unrelated_type_equality_checks
- // use_function_type_syntax_for_parameters
// valid_regexps
static final alwaysDeclareReturnTypes = LintFixInfo(
@@ -380,6 +379,12 @@
isPedantic: true,
);
+ static final preferIterableWhereType = LintFixInfo(
+ 'prefer_iterable_whereType',
+ DartFixKind.CONVERT_TO_WHERE_TYPE,
+ 'Add a return type where possible.',
+ isPedantic: true);
+
static final preferSingleQuotes = LintFixInfo(
'prefer_single_quotes',
DartFixKind.CONVERT_TO_SINGLE_QUOTED_STRING,
@@ -439,10 +444,22 @@
isPedantic: true,
);
+ static final unnecessaryNullInIfNullOperators = LintFixInfo(
+ 'unnecessary_null_in_if_null_operators',
+ DartFixKind.REMOVE_IF_NULL_OPERATOR,
+ "Remove the '??' operator.",
+ isPedantic: true);
+
static final unnecessaryThis = LintFixInfo(
'unnecessary_this', DartFixKind.REMOVE_THIS_EXPRESSION, 'Remove this.',
isPedantic: true);
+ static final useFunctionTypeSyntaxForParameters = LintFixInfo(
+ 'use_function_type_syntax_for_parameters',
+ DartFixKind.CONVERT_TO_GENERIC_FUNCTION_SYNTAX,
+ "Convert into 'Function' syntax",
+ isPedantic: true);
+
static final useRethrowWhenPossible = LintFixInfo('use_rethrow_when_possible',
DartFixKind.USE_RETHROW, 'Replace with rethrow.',
isPedantic: true);
diff --git a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
index 7e10dfe..014f4c5 100644
--- a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
@@ -20,7 +20,7 @@
import 'package:analyzer/src/lint/registry.dart';
class PreferMixinFix extends FixLintTask implements FixCodeTask {
- final classesToConvert = Set<Element>();
+ final classesToConvert = <Element>{};
PreferMixinFix(DartFixListener listener) : super(listener);
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 fc54798..dcf9223 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
@@ -169,6 +169,11 @@
nullableValue = "a nullable value";
}
+ if (origin.kind == EdgeOriginKind.listLengthConstructor) {
+ return "List value type must be nullable because a length is specified,"
+ " and the list items are initialized as null.";
+ }
+
CompilationUnit unit = node.thisOrAncestorOfType<CompilationUnit>();
int lineNumber = unit.lineInfo.getLocation(node.offset).lineNumber;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 0d38d2c..f53de11 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -109,7 +109,7 @@
final key =
_createImportedSymbolKey(elementName, declaringLibraryUri);
- alreadyImportedSymbols.putIfAbsent(key, () => Set<String>());
+ alreadyImportedSymbols.putIfAbsent(key, () => <String>{});
alreadyImportedSymbols[key]
.add('${importedLibrary.librarySource.uri}');
}
@@ -140,8 +140,8 @@
Set<String> includedElementNames;
List<IncludedSuggestionRelevanceTag> includedSuggestionRelevanceTags;
if (includeSuggestionSets) {
- includedElementKinds = Set<ElementKind>();
- includedElementNames = Set<String>();
+ includedElementKinds = <ElementKind>{};
+ includedElementNames = <String>{};
includedSuggestionRelevanceTags = <IncludedSuggestionRelevanceTag>[];
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
index 4c26bb0..eeee66f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
@@ -9,6 +9,83 @@
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+/// Helper for reading client dynamic registrations which may be ommitted by the
+/// client.
+class ClientDynamicRegistrations {
+ /// All dynamic registrations supported by the Dart LSP server.
+ ///
+ /// Anything listed here and supported by the client will not send a static
+ /// registration but intead dynamically register (usually only for a subset of
+ /// files such as for .dart/pubspec.yaml/etc).
+ ///
+ /// When adding new capabilities that will be registered dynamically, the
+ /// test_dynamicRegistration_XXX tests in `lsp/initialization_test.dart` should
+ /// also be updated to ensure no double-registrations.
+ static const supported = [
+ Method.textDocument_didOpen,
+ Method.textDocument_didChange,
+ Method.textDocument_didClose,
+ Method.textDocument_completion,
+ Method.textDocument_hover,
+ Method.textDocument_signatureHelp,
+ Method.textDocument_references,
+ Method.textDocument_documentHighlight,
+ Method.textDocument_formatting,
+ Method.textDocument_onTypeFormatting,
+ Method.textDocument_definition,
+ Method.textDocument_codeAction,
+ Method.textDocument_rename,
+ Method.textDocument_foldingRange,
+ ];
+ final ClientCapabilities _capabilities;
+
+ ClientDynamicRegistrations(this._capabilities);
+
+ bool get codeActions =>
+ _capabilities.textDocument?.foldingRange?.dynamicRegistration ?? false;
+
+ bool get completion =>
+ _capabilities.textDocument?.completion?.dynamicRegistration ?? false;
+
+ bool get definition =>
+ _capabilities.textDocument?.definition?.dynamicRegistration ?? false;
+
+ bool get documentHighlights =>
+ _capabilities.textDocument?.documentHighlight?.dynamicRegistration ??
+ false;
+
+ bool get documentSymbol =>
+ _capabilities.textDocument?.documentSymbol?.dynamicRegistration ?? false;
+
+ bool get folding =>
+ _capabilities.textDocument?.foldingRange?.dynamicRegistration ?? false;
+
+ bool get formatting =>
+ _capabilities.textDocument?.formatting?.dynamicRegistration ?? false;
+
+ bool get hover =>
+ _capabilities.textDocument?.hover?.dynamicRegistration ?? false;
+
+ bool get implementation =>
+ _capabilities.textDocument?.implementation?.dynamicRegistration ?? false;
+
+ bool get references =>
+ _capabilities.textDocument?.references?.dynamicRegistration ?? false;
+
+ bool get rename =>
+ _capabilities.textDocument?.rename?.dynamicRegistration ?? false;
+
+ bool get signatureHelp =>
+ _capabilities.textDocument?.signatureHelp?.dynamicRegistration ?? false;
+
+ bool get textSync =>
+ _capabilities.textDocument?.synchronization?.dynamicRegistration ?? false;
+
+ bool get typeFormatting =>
+ _capabilities.textDocument?.onTypeFormatting?.dynamicRegistration ??
+ false;
+}
+
class InitializeMessageHandler
extends MessageHandler<InitializeParams, InitializeResult> {
InitializeMessageHandler(LspAnalysisServer server) : super(server);
@@ -143,80 +220,3 @@
return success(InitializeResult(server.capabilities));
}
}
-
-/// Helper for reading client dynamic registrations which may be ommitted by the
-/// client.
-class ClientDynamicRegistrations {
- ClientCapabilities _capabilities;
- ClientDynamicRegistrations(this._capabilities);
-
- /// All dynamic registrations supported by the Dart LSP server.
- ///
- /// Anything listed here and supported by the client will not send a static
- /// registration but intead dynamically register (usually only for a subset of
- /// files such as for .dart/pubspec.yaml/etc).
- ///
- /// When adding new capabilities that will be registered dynamically, the
- /// test_dynamicRegistration_XXX tests in `lsp/initialization_test.dart` should
- /// also be updated to ensure no double-registrations.
- static const supported = [
- Method.textDocument_didOpen,
- Method.textDocument_didChange,
- Method.textDocument_didClose,
- Method.textDocument_completion,
- Method.textDocument_hover,
- Method.textDocument_signatureHelp,
- Method.textDocument_references,
- Method.textDocument_documentHighlight,
- Method.textDocument_formatting,
- Method.textDocument_onTypeFormatting,
- Method.textDocument_definition,
- Method.textDocument_codeAction,
- Method.textDocument_rename,
- Method.textDocument_foldingRange,
- ];
-
- bool get textSync =>
- _capabilities.textDocument?.synchronization?.dynamicRegistration ?? false;
-
- bool get hover =>
- _capabilities.textDocument?.hover?.dynamicRegistration ?? false;
-
- bool get completion =>
- _capabilities.textDocument?.completion?.dynamicRegistration ?? false;
-
- bool get signatureHelp =>
- _capabilities.textDocument?.signatureHelp?.dynamicRegistration ?? false;
-
- bool get definition =>
- _capabilities.textDocument?.definition?.dynamicRegistration ?? false;
-
- bool get implementation =>
- _capabilities.textDocument?.implementation?.dynamicRegistration ?? false;
-
- bool get references =>
- _capabilities.textDocument?.references?.dynamicRegistration ?? false;
-
- bool get documentHighlights =>
- _capabilities.textDocument?.documentHighlight?.dynamicRegistration ??
- false;
-
- bool get documentSymbol =>
- _capabilities.textDocument?.documentSymbol?.dynamicRegistration ?? false;
-
- bool get formatting =>
- _capabilities.textDocument?.formatting?.dynamicRegistration ?? false;
-
- bool get typeFormatting =>
- _capabilities.textDocument?.onTypeFormatting?.dynamicRegistration ??
- false;
-
- bool get folding =>
- _capabilities.textDocument?.foldingRange?.dynamicRegistration ?? false;
-
- bool get codeActions =>
- _capabilities.textDocument?.foldingRange?.dynamicRegistration ?? false;
-
- bool get rename =>
- _capabilities.textDocument?.rename?.dynamicRegistration ?? false;
-}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
index b941473..4ad092f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
@@ -52,7 +52,7 @@
// huge numbers on large projects.
var remainingResults = 500;
- final filePathsHashSet = LinkedHashSet<String>();
+ final filePathsHashSet = <String>{};
final tracker = server.declarationsTracker;
final declarations = search.WorkspaceSymbols(tracker).declarations(
regex,
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 8f0d3f7..eaa0423 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -713,8 +713,8 @@
@override
ContextBuilder createContextBuilder(Folder folder, AnalysisOptions options) {
- String defaultPackageFilePath = null;
- String defaultPackagesDirectoryPath = null;
+ String defaultPackageFilePath;
+ String defaultPackagesDirectoryPath;
String path = (analysisServer.contextManager as ContextManagerImpl)
.normalizedPackageRoots[folder.path];
if (path != null) {
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
index ad7d7b9..7b170e9 100644
--- a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
+++ b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
@@ -462,7 +462,7 @@
bool matches(String pattern) =>
Glob(resourceProvider.pathContext.separator, pattern).matches(filePath);
- WatchEvent event = null;
+ WatchEvent event;
List<Future<Response>> responses = <Future<Response>>[];
for (PluginInfo plugin in _pluginMap.values) {
PluginSession session = plugin.currentSession;
diff --git a/pkg/analysis_server/lib/src/plugin/result_merger.dart b/pkg/analysis_server/lib/src/plugin/result_merger.dart
index c03d992..e711295 100644
--- a/pkg/analysis_server/lib/src/plugin/result_merger.dart
+++ b/pkg/analysis_server/lib/src/plugin/result_merger.dart
@@ -211,7 +211,7 @@
KytheGetKytheEntriesResult mergeKytheEntries(
List<KytheGetKytheEntriesResult> partialResultList) {
List<KytheEntry> mergedEntries = <KytheEntry>[];
- Set<String> mergedFiles = Set<String>();
+ Set<String> mergedFiles = <String>{};
for (KytheGetKytheEntriesResult partialResult in partialResultList) {
mergedEntries.addAll(partialResult.entries);
mergedFiles.addAll(partialResult.files);
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 0970df2..7929337 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'dart:collection';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/src/analysis_server.dart';
@@ -188,7 +187,7 @@
}
var tracker = server.declarationsTracker;
- var files = LinkedHashSet<String>();
+ var files = <String>{};
int remainingMaxResults = params.maxResults;
var declarations = search.WorkspaceSymbols(tracker).declarations(
regExp,
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index c196526..8ed15b2 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -117,7 +117,7 @@
// create an empty item now
int itemId;
{
- String displayName = null;
+ String displayName;
if (typeArguments != null && typeArguments.isNotEmpty) {
displayName =
classElement.displayName + '<' + typeArguments.join(', ') + '>';
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_performance.dart b/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
index b4feecc..264b161 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
@@ -7,7 +7,7 @@
*/
class CompletionPerformance {
final DateTime start = DateTime.now();
- final Map<String, Duration> _startTimes = Map<String, Duration>();
+ final Map<String, Duration> _startTimes = <String, Duration>{};
final Stopwatch _stopwatch = Stopwatch();
final List<OperationPerformance> operations = <OperationPerformance>[];
@@ -31,7 +31,7 @@
return '$suggestionCountFirst, $suggestionCountLast';
}
- void complete([String tag = null]) {
+ void complete([String tag]) {
_stopwatch.stop();
_logDuration(tag ?? 'total time', _stopwatch.elapsed);
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index c179134..c2dbb1e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -120,7 +120,7 @@
*/
Iterable<String> _namedArgs(DartCompletionRequest request) {
AstNode node = request.target.containingNode;
- List<String> namedArgs = List<String>();
+ List<String> namedArgs = <String>[];
if (node is ArgumentList) {
for (Expression arg in node.arguments) {
if (arg is NamedExpression) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
index 7c6947d..7456648 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
@@ -169,7 +169,7 @@
return null;
}
- final result = List<String>();
+ final result = <String>[];
for (var size = 0;
size < n && token != null && !token.isEof;
token = token.previous) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index 2eab3cb..0d6f12a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -62,11 +62,13 @@
// to ensure that we can return the suggestions from other providers.
return const <CompletionSuggestion>[];
}
+ var typeSystem = containingLibrary.typeSystem;
LibraryScope nameScope = LibraryScope(containingLibrary);
for (var extension in nameScope.extensions) {
var extendedType =
_resolveExtendedType(containingLibrary, extension, type);
- if (extendedType != null) {
+ if (extendedType != null &&
+ typeSystem.isSubtypeOf(type, extendedType)) {
// TODO(brianwilkerson) We might want to apply the substitution to the
// members of the extension for display purposes.
_addInstanceMembers(extension);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
index 739ab98..4617cb5 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
@@ -31,7 +31,7 @@
}
// Compute the list of fields already referenced in the constructor
- List<String> referencedFields = List<String>();
+ List<String> referencedFields = <String>[];
for (FormalParameter param in constructor.parameters.parameters) {
if (param is DefaultFormalParameter &&
param.parameter is FieldFormalParameter) {
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 924029c..9f939de 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
@@ -177,7 +177,7 @@
@override
visitCompilationUnit(CompilationUnit node) {
- var previousMember = null;
+ var previousMember;
for (var member in node.childEntities) {
if (entity == member) {
break;
@@ -341,13 +341,8 @@
previous = node.findPrevious(previous);
}
if (previous != null && previous.type == TokenType.EQ) {
- _addSuggestions([
- Keyword.CONST,
- Keyword.FALSE,
- Keyword.NEW,
- Keyword.NULL,
- Keyword.TRUE
- ]);
+ _addSuggestions(
+ [Keyword.CONST, Keyword.FALSE, Keyword.NULL, Keyword.TRUE]);
} else {
_addSuggestion(Keyword.IN, DART_RELEVANCE_HIGH);
}
@@ -735,7 +730,6 @@
_addSuggestions([
Keyword.CONST,
Keyword.FALSE,
- Keyword.NEW,
Keyword.NULL,
Keyword.TRUE,
]);
@@ -829,7 +823,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart b/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart
index 8b90e92..5f59c73 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart
@@ -108,8 +108,8 @@
// Get scores (as floats)
final probabilities = Float32List.view(bytes.buffer);
- final scores = Map<String, double>();
- final scoresAboveThreshold = Map<String, double>();
+ final scores = <String, double>{};
+ final scoresAboveThreshold = <String, double>{};
probabilities.asMap().forEach((k, v) {
// x in 0, 1, ..., |V| - 1 correspond to specific members of the vocabulary.
// x in |V|, |V| + 1, ..., |V| + 49 are pointers to reference positions along the
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
index 8edb690..290468a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
@@ -34,7 +34,7 @@
/**
* The set of libraries that have been, or are currently being, visited.
*/
- final Set<LibraryElement> visitedLibraries = Set<LibraryElement>();
+ final Set<LibraryElement> visitedLibraries = <LibraryElement>{};
LibraryElementSuggestionBuilder(this.request, this.optype, [this.prefix]) {
kind = request.target.isFunctionalArgument()
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index ba5457b..d66685c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -533,7 +533,7 @@
.map((FormalParameter param) => param.identifier.name)
.toList();
suggestion.parameterTypes = paramList.map((FormalParameter param) {
- TypeAnnotation type = null;
+ TypeAnnotation type;
if (param is DefaultFormalParameter) {
NormalFormalParameter child = param.parameter;
if (child is SimpleFormalParameter) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 224a945..9d248a4 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -92,7 +92,7 @@
/**
* A set of existing completions used to prevent duplicate suggestions.
*/
- final Set<String> _completions = Set<String>();
+ final Set<String> _completions = <String>{};
/**
* A map of element names to suggestions for synthetic getters and setters.
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
index dc3023a..f039010 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/variable_name_contributor.dart
@@ -67,7 +67,7 @@
node = CompletionTarget.findFormalParameter(node, offset);
}
- String strName = null;
+ String strName;
if (node is ExpressionStatement) {
var expression = node.expression;
if (expression is Identifier) {
diff --git a/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart b/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
index 3163f19..184da5f 100644
--- a/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
@@ -293,7 +293,7 @@
PostfixCompletion completion;
SourceChange change = SourceChange('postfix-completion');
final Map<String, LinkedEditGroup> linkedPositionGroups = {};
- Position exitPosition = null;
+ Position exitPosition;
PostfixCompletionProcessor(this.completionContext)
: utils = CorrectionUtils(completionContext.resolveResult);
@@ -548,7 +548,7 @@
return expr;
}
- AstNode _selectedNode({int at = null}) =>
+ AstNode _selectedNode({int at}) =>
NodeLocator(at == null ? selectionOffset : at)
.searchWithin(completionContext.resolveResult.unit);
diff --git a/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart b/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
index 4332b1f..4199bc8 100644
--- a/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
@@ -132,7 +132,7 @@
List<engine.AnalysisError> errors = [];
final Map<String, LinkedEditGroup> linkedPositionGroups =
<String, LinkedEditGroup>{};
- Position exitPosition = null;
+ Position exitPosition;
StatementCompletionProcessor(this.statementContext)
: utils = CorrectionUtils(statementContext.resolveResult);
@@ -268,7 +268,7 @@
void _checkExpressions() {
// Note: This may queue edits that have to be accounted for later.
// See _lengthOfInsertions().
- AstNode errorMatching(errorCode, {partialMatch = null}) {
+ AstNode errorMatching(errorCode, {partialMatch}) {
var error = _findError(errorCode, partialMatch: partialMatch);
if (error == null) {
return null;
@@ -1091,7 +1091,7 @@
return false;
}
- engine.AnalysisError _findError(ErrorCode code, {partialMatch = null}) {
+ engine.AnalysisError _findError(ErrorCode code, {partialMatch}) {
return errors.firstWhere(
(err) =>
err.errorCode == code &&
@@ -1194,14 +1194,14 @@
return Position(file, offset);
}
- void _removeError(errorCode, {partialMatch = null}) {
+ void _removeError(errorCode, {partialMatch}) {
var error = _findError(errorCode, partialMatch: partialMatch);
if (error != null) {
errors.remove(error);
}
}
- AstNode _selectedNode({int at = null}) =>
+ AstNode _selectedNode({int at}) =>
NodeLocator(at == null ? selectionOffset : at).searchWithin(unit);
void _setCompletion(StatementCompletionKind kind, [List args]) {
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 af3972a..57f0293 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -223,7 +223,7 @@
}
void _addAssistFromBuilder(DartChangeBuilder builder, AssistKind kind,
- {List args = null}) {
+ {List args}) {
if (builder == null) {
return;
}
@@ -395,7 +395,7 @@
return;
}
// prepare excluded names
- Set<String> excluded = Set<String>();
+ Set<String> excluded = <String>{};
ScopedNameFinder scopedNameFinder = ScopedNameFinder(offset);
expression.accept(scopedNameFinder);
excluded.addAll(scopedNameFinder.locals.keys.toSet());
@@ -1051,8 +1051,8 @@
*/
Future<void> _addProposal_convertToIsNotEmpty() async {
// prepare "expr.isEmpty"
- AstNode isEmptyAccess = null;
- SimpleIdentifier isEmptyIdentifier = null;
+ AstNode isEmptyAccess;
+ SimpleIdentifier isEmptyIdentifier;
if (node is SimpleIdentifier) {
SimpleIdentifier identifier = node as SimpleIdentifier;
AstNode parent = identifier.parent;
@@ -1357,7 +1357,7 @@
String stateName = '_${widgetName}State';
// Find fields assigned in constructors.
- var fieldsAssignedInConstructors = Set<FieldElement>();
+ var fieldsAssignedInConstructors = <FieldElement>{};
for (var member in widgetClass.members) {
if (member is ConstructorDeclaration) {
member.accept(_SimpleIdentifierRecursiveAstVisitor((node) {
@@ -1387,8 +1387,8 @@
}
// Prepare nodes to move.
- var nodesToMove = Set<ClassMember>();
- var elementsToMove = Set<Element>();
+ var nodesToMove = <ClassMember>{};
+ var elementsToMove = <Element>{};
for (var member in widgetClass.members) {
if (member is FieldDeclaration && !member.isStatic) {
for (VariableDeclaration fieldNode in member.fields.variables) {
@@ -2065,7 +2065,7 @@
statementPrefix = '';
}
// prepare excluded names
- Set<String> excluded = Set<String>();
+ Set<String> excluded = <String>{};
ScopedNameFinder scopedNameFinder = ScopedNameFinder(offset);
isExpression.accept(scopedNameFinder);
excluded.addAll(scopedNameFinder.locals.keys.toSet());
@@ -2442,7 +2442,7 @@
}
Future<void> _addProposal_replaceConditionalWithIfElse() async {
- ConditionalExpression conditional = null;
+ ConditionalExpression conditional;
// may be on Statement with Conditional
Statement statement = node.thisOrAncestorOfType<Statement>();
if (statement == null) {
@@ -2559,8 +2559,8 @@
_coverageMarker();
return;
}
- Expression thenExpression = null;
- Expression elseExpression = null;
+ Expression thenExpression;
+ Expression elseExpression;
bool hasReturnStatements = false;
if (thenStatement is ReturnStatement && elseStatement is ReturnStatement) {
hasReturnStatements = true;
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 dca2f02..8d6fbad 100644
--- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -458,7 +458,7 @@
String elementText;
ConvertToSpreadCollectionsChange change =
ConvertToSpreadCollectionsChange();
- List<String> args = null;
+ List<String> args;
if (argument is BinaryExpression &&
argument.operator.type == TokenType.QUESTION_QUESTION) {
Expression right = argument.rightOperand;
@@ -1584,7 +1584,7 @@
/// A collection of the names of other simple identifiers that were found. We
/// need to know these in order to ensure that the selected loop variable does
/// not hide a name from an enclosing scope that is already being referenced.
- final Set<String> otherNames = Set<String>();
+ final Set<String> otherNames = <String>{};
/// Initialize a newly created finder to find references to the [parameter].
_ParameterReferenceFinder(this.parameter) : assert(parameter != null);
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_where_type.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_where_type.dart
new file mode 100644
index 0000000..76354ec
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_where_type.dart
@@ -0,0 +1,53 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class ConvertToWhereType extends CorrectionProducer {
+ @override
+ Future<void> compute(DartChangeBuilder builder) async {
+ AstNode node = this.node;
+ if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
+ return;
+ }
+ var methodName = node as SimpleIdentifier;
+ var invocation = node.parent as MethodInvocation;
+ var arguments = invocation.argumentList.arguments;
+ if (arguments.length != 1 || arguments[0] is! FunctionExpression) {
+ return;
+ }
+ var body = (arguments[0] as FunctionExpression).body;
+ Expression returnValue;
+ if (body is ExpressionFunctionBody) {
+ returnValue = body.expression;
+ } else if (body is BlockFunctionBody) {
+ var statements = body.block.statements;
+ if (statements.length != 1 || statements[0] is! ReturnStatement) {
+ return;
+ }
+ returnValue = (statements[0] as ReturnStatement).expression;
+ } else {
+ return;
+ }
+ if (returnValue is! IsExpression) {
+ return;
+ }
+ var isExpression = returnValue as IsExpression;
+ if (isExpression.notOperator != null) {
+ return;
+ }
+ var targetType = isExpression.type;
+
+ await builder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addReplacement(range.startEnd(methodName, invocation), (builder) {
+ builder.write('whereType<');
+ builder.write(utils.getNodeText(targetType));
+ builder.write('>()');
+ });
+ });
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/exchange_operands.dart b/pkg/analysis_server/lib/src/services/correction/dart/exchange_operands.dart
index 6131b48..b9a9a5d 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/exchange_operands.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/exchange_operands.dart
@@ -39,7 +39,7 @@
// maybe replace the operator
Token operator = binaryExpression.operator;
// prepare a new operator
- String newOperator = null;
+ String newOperator;
TokenType operatorType = operator.type;
if (operatorType == TokenType.LT) {
newOperator = '>';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_if_null_operator.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_if_null_operator.dart
new file mode 100644
index 0000000..23ac078
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_if_null_operator.dart
@@ -0,0 +1,32 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class RemoveIfNullOperator extends CorrectionProducer {
+ @override
+ Future<void> compute(DartChangeBuilder builder) async {
+ var expression = node.thisOrAncestorOfType<BinaryExpression>();
+ if (expression == null) {
+ return;
+ }
+ SourceRange sourceRange;
+ if (expression.leftOperand.unParenthesized is NullLiteral) {
+ sourceRange =
+ range.startStart(expression.leftOperand, expression.rightOperand);
+ } else if (expression.rightOperand.unParenthesized is NullLiteral) {
+ sourceRange =
+ range.endEnd(expression.leftOperand, expression.rightOperand);
+ } else {
+ return;
+ }
+ await builder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addDeletion(sourceRange);
+ });
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 97d489e..2d3348d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -220,6 +220,8 @@
'CONVERT_TO_SINGLE_QUOTED_STRING', 50, "Convert to single quoted string");
static const CONVERT_TO_SPREAD =
FixKind('CONVERT_TO_SPREAD', 50, "Convert to a spread");
+ static const CONVERT_TO_WHERE_TYPE =
+ FixKind('CONVERT_TO_WHERE_TYPE', 50, "Convert to a use 'whereType'");
static const CREATE_CLASS = FixKind('CREATE_CLASS', 50, "Create class '{0}'");
static const CREATE_CONSTRUCTOR =
FixKind('CREATE_CONSTRUCTOR', 50, "Create constructor '{0}'");
@@ -295,6 +297,8 @@
FixKind('REMOVE_EMPTY_ELSE', 50, "Remove empty else clause");
static const REMOVE_EMPTY_STATEMENT =
FixKind('REMOVE_EMPTY_STATEMENT', 50, "Remove empty statement");
+ static const REMOVE_IF_NULL_OPERATOR =
+ FixKind('REMOVE_IF_NULL_OPERATOR', 50, "Remove the '??' operator");
static const REMOVE_INITIALIZER =
FixKind('REMOVE_INITIALIZER', 50, "Remove initializer");
static const REMOVE_INTERPOLATION_BRACES = FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart
index 35a8632..d0806ae 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart
@@ -148,8 +148,7 @@
/// Add a fix whose edits were built by the [builder] that has the given
/// [kind]. If [args] are provided, they will be used to fill in the message
/// for the fix.
- void _addFixFromBuilder(ChangeBuilder builder, FixKind kind,
- {List args = null}) {
+ void _addFixFromBuilder(ChangeBuilder builder, FixKind kind, {List args}) {
SourceChange change = builder.sourceChange;
if (change.edits.isEmpty) {
return;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart
index f087468..6d2bb89 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart
@@ -114,8 +114,7 @@
/// [kind]. If [args] are provided, they will be used to fill in the message
/// for the fix.
// ignore: unused_element
- void _addFixFromBuilder(ChangeBuilder builder, FixKind kind,
- {List args = null}) {
+ void _addFixFromBuilder(ChangeBuilder builder, FixKind kind, {List args}) {
SourceChange change = builder.sourceChange;
if (change.edits.isEmpty) {
return;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart
index 0f4b10c..4c6bf66 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart
@@ -72,8 +72,7 @@
/// [kind]. If [args] are provided, they will be used to fill in the message
/// for the fix.
// ignore: unused_element
- void _addFixFromBuilder(ChangeBuilder builder, FixKind kind,
- {List args = null}) {
+ void _addFixFromBuilder(ChangeBuilder builder, FixKind kind, {List args}) {
SourceChange change = builder.sourceChange;
if (change.edits.isEmpty) {
return;
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 22926d1..3501f4c 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -11,7 +11,12 @@
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/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';
+import 'package:analysis_server/src/services/correction/dart/convert_to_set_literal.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_where_type.dart';
+import 'package:analysis_server/src/services/correction/dart/remove_if_null_operator.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/correction/levenshtein.dart';
@@ -54,9 +59,6 @@
import 'package:analyzer_plugin/utilities/fixes/fixes.dart' hide FixContributor;
import 'package:analyzer_plugin/utilities/range_factory.dart';
import 'package:path/path.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_set_literal.dart';
/**
* A predicate is a one-argument function that returns a boolean value.
@@ -116,7 +118,7 @@
final List<Fix> fixesListI = await processorI.compute();
for (Fix f in fixesListI) {
if (!map.containsKey(f.kind)) {
- map[f.kind] = List<Fix>()..add(f);
+ map[f.kind] = <Fix>[]..add(f);
} else {
map[f.kind].add(f);
}
@@ -125,7 +127,7 @@
// For each FixKind in the HashMap, union each list together, then return
// the set of unioned Fixes.
- final List<Fix> result = List<Fix>();
+ final List<Fix> result = <Fix>[];
map.forEach((FixKind kind, List<Fix> fixesListJ) {
if (fixesListJ.first.kind.canBeAppliedTogether()) {
Fix unionFix = _unionFixList(fixesListJ);
@@ -146,7 +148,7 @@
final SourceChange sourceChange =
SourceChange(fixList[0].kind.appliedTogetherMessage);
sourceChange.edits = List.from(fixList[0].change.edits);
- final List<SourceEdit> edits = List<SourceEdit>();
+ final List<SourceEdit> edits = <SourceEdit>[];
edits.addAll(fixList[0].change.edits[0].edits);
sourceChange.linkedEditGroups =
List.from(fixList[0].change.linkedEditGroups);
@@ -646,6 +648,9 @@
if (name == LintNames.empty_statements) {
await _addFix_removeEmptyStatement();
}
+ if (name == LintNames.hash_and_equals) {
+ await _addFix_addMissingHashOrEquals();
+ }
if (name == LintNames.no_duplicate_case_values) {
await _addFix_removeCaseStatement();
}
@@ -747,6 +752,9 @@
if (name == LintNames.unnecessary_this) {
await _addFix_removeThisExpression();
}
+ if (name == LintNames.use_function_type_syntax_for_parameters) {
+ await _addFix_convertToGenericFunctionSyntax();
+ }
if (name == LintNames.use_rethrow_when_possible) {
await _addFix_replaceWithRethrow();
}
@@ -973,6 +981,42 @@
changeBuilder, DartFixKind.ADD_MISSING_ENUM_CASE_CLAUSES);
}
+ Future<void> _addFix_addMissingHashOrEquals() async {
+ final methodDecl = node.thisOrAncestorOfType<MethodDeclaration>();
+ final classDecl = node.thisOrAncestorOfType<ClassDeclaration>();
+ if (methodDecl != null && classDecl != null) {
+ final classElement = classDecl.declaredElement;
+
+ var element;
+ var memberName;
+ if (methodDecl.name.name == 'hashCode') {
+ memberName = '==';
+ element = classElement.lookUpInheritedMethod(
+ memberName, classElement.library);
+ } else {
+ memberName = 'hashCode';
+ element = classElement.lookUpInheritedConcreteGetter(
+ memberName, classElement.library);
+ }
+
+ final location =
+ utils.prepareNewClassMemberLocation(classDecl, (_) => true);
+
+ final changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (fileBuilder) {
+ fileBuilder.addInsertion(location.offset, (builder) {
+ builder.write(location.prefix);
+ builder.writeOverride(element, invokeSuper: true);
+ builder.write(location.suffix);
+ });
+ });
+
+ changeBuilder.setSelection(Position(file, location.offset));
+ _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD,
+ args: [memberName]);
+ }
+ }
+
Future<void> _addFix_addMissingParameter() async {
// The error is reported on ArgumentList.
if (node is! ArgumentList) {
@@ -1002,7 +1046,7 @@
builder.addInsertion(offset, (builder) {
builder.write(prefix);
builder.writeParameterMatchingArgument(
- argument, numRequired, Set<String>());
+ argument, numRequired, <String>{});
builder.write(suffix);
});
});
@@ -1076,8 +1120,8 @@
await changeBuilder.addFileEdit(context.file, (builder) {
builder.addInsertion(offset, (builder) {
builder.write(prefix);
- builder.writeParameterMatchingArgument(
- namedExpression, 0, Set<String>());
+ builder
+ .writeParameterMatchingArgument(namedExpression, 0, <String>{});
builder.write(suffix);
});
});
@@ -1582,7 +1626,7 @@
argumentList.arguments.skip(numberOfPositionalParameters);
for (var argument in extraArguments) {
if (argument is! NamedExpression) {
- ParameterElement uniqueNamedParameter = null;
+ ParameterElement uniqueNamedParameter;
for (var namedParameter in namedParameters) {
if (typeSystem.isSubtypeOf(
argument.staticType, namedParameter.type)) {
@@ -1626,8 +1670,8 @@
}
Future<void> _addFix_createClass() async {
- Element prefixElement = null;
- String name = null;
+ Element prefixElement;
+ String name;
SimpleIdentifier nameNode;
if (node is SimpleIdentifier) {
AstNode parent = node.parent;
@@ -1841,9 +1885,9 @@
}
Future<void> _addFix_createConstructor_named() async {
- SimpleIdentifier name = null;
- ConstructorName constructorName = null;
- InstanceCreationExpression instanceCreation = null;
+ SimpleIdentifier name;
+ ConstructorName constructorName;
+ InstanceCreationExpression instanceCreation;
if (node is SimpleIdentifier) {
// name
name = node as SimpleIdentifier;
@@ -2530,8 +2574,8 @@
}
Future<void> _addFix_createMixin() async {
- Element prefixElement = null;
- String name = null;
+ Element prefixElement;
+ String name;
SimpleIdentifier nameNode;
if (node is SimpleIdentifier) {
AstNode parent = node.parent;
@@ -2784,7 +2828,7 @@
}
Future<void> _addFix_importLibrary(FixKind kind, Uri library,
- [String relativeURI = null]) async {
+ [String relativeURI]) async {
String uriText;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@@ -2813,7 +2857,7 @@
}
// may be there is an existing import,
// but it is with prefix and we don't use this prefix
- var alreadyImportedWithPrefix = Set<String>();
+ var alreadyImportedWithPrefix = <String>{};
for (ImportElement imp in unitLibraryElement.imports) {
// prepare element
LibraryElement libraryElement = imp.importedLibrary;
@@ -3184,7 +3228,7 @@
}
SimpleIdentifier memberName = node;
AstNode parent = node.parent;
- AstNode target = null;
+ AstNode target;
if (parent is MethodInvocation && node == parent.methodName) {
target = parent.target;
} else if (parent is PropertyAccess && node == parent.propertyName) {
@@ -4051,7 +4095,7 @@
return;
}
AstNode parent = node.parent;
- AstNode target = null;
+ AstNode target;
if (parent is MethodInvocation && node == parent.methodName) {
target = parent.target;
} else if (parent is PropertyAccess && node == parent.propertyName) {
@@ -4238,7 +4282,7 @@
Future<void> _addFix_undefinedClass_useSimilar() async {
AstNode node = this.node;
// Prepare the optional import prefix name.
- String prefixName = null;
+ String prefixName;
if (node is SimpleIdentifier && node.staticElement is PrefixElement) {
AstNode parent = node.parent;
if (parent is PrefixedIdentifier &&
@@ -4288,7 +4332,7 @@
AstNode node = this.node;
if (node is SimpleIdentifier) {
// prepare target
- Expression target = null;
+ Expression target;
if (node.parent is PrefixedIdentifier) {
target = (node.parent as PrefixedIdentifier).prefix;
} else if (node.parent is PropertyAccess) {
@@ -4401,7 +4445,7 @@
AstNode node = this.node;
if (node is SimpleIdentifier) {
// Prepare the optional import prefix name.
- String prefixName = null;
+ String prefixName;
{
AstNode invocation = node.parent;
if (invocation is MethodInvocation && invocation.methodName == node) {
@@ -4517,7 +4561,7 @@
Future<void> _addFix_updateSdkConstraints(String minimumVersion) async {
Context context = resourceProvider.pathContext;
- File pubspecFile = null;
+ File pubspecFile;
Folder folder = resourceProvider.getFolder(context.dirname(file));
while (folder != null) {
pubspecFile = folder.getChildAssumingFile('pubspec.yaml');
@@ -4626,7 +4670,7 @@
}
void _addFixFromBuilder(ChangeBuilder builder, FixKind kind,
- {List args = null, bool importsOnly = false}) {
+ {List args, bool importsOnly = false}) {
if (builder == null) return;
SourceChange change = builder.sourceChange;
if (change.edits.isEmpty && !importsOnly) {
@@ -4674,11 +4718,21 @@
ConvertToSetLiteral(),
DartFixKind.CONVERT_TO_SET_LITERAL,
);
+ } else if (name == LintNames.prefer_iterable_whereType) {
+ await compute(
+ ConvertToWhereType(),
+ DartFixKind.CONVERT_TO_WHERE_TYPE,
+ );
} else if (name == LintNames.prefer_null_aware_operators) {
await compute(
ConvertToNullAware(),
DartFixKind.CONVERT_TO_NULL_AWARE,
);
+ } else if (name == LintNames.unnecessary_null_in_if_null_operators) {
+ await compute(
+ RemoveIfNullOperator(),
+ DartFixKind.REMOVE_IF_NULL_OPERATOR,
+ );
}
}
}
@@ -5201,7 +5255,7 @@
final String _targetName;
final ElementPredicate _predicate;
- Element _element = null;
+ Element _element;
int _distance;
_ClosestElementFinder(this._targetName, this._predicate, this._distance);
diff --git a/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart b/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart
index 5ca1d68..1f3b3ef 100644
--- a/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart
+++ b/pkg/analysis_server/lib/src/services/correction/name_suggestion.dart
@@ -46,7 +46,7 @@
}
}
- Set<String> res = Set();
+ Set<String> res = {};
// use expression
if (assignedExpression != null) {
String nameFromExpression = _getBaseNameFromExpression(assignedExpression);
@@ -108,7 +108,7 @@
text = sb.toString();
}
// split camel-case into separate suggested names
- Set<String> res = Set();
+ Set<String> res = {};
_addAll(excluded, res, getCamelWordCombinations(text));
return List.from(res);
}
@@ -178,7 +178,7 @@
}
String _getBaseNameFromUnwrappedExpression(Expression expression) {
- String name = null;
+ String name;
// analyze expressions
if (expression is SimpleIdentifier) {
return expression.name;
diff --git a/pkg/analysis_server/lib/src/services/correction/namespace.dart b/pkg/analysis_server/lib/src/services/correction/namespace.dart
index a57f4d1..627fc30 100644
--- a/pkg/analysis_server/lib/src/services/correction/namespace.dart
+++ b/pkg/analysis_server/lib/src/services/correction/namespace.dart
@@ -60,7 +60,7 @@
}
LibraryElement usedLibrary = element.library;
// find ImportElement that imports used library with used prefix
- List<ImportElement> candidates = null;
+ List<ImportElement> candidates;
for (ImportElement importElement in libraryElement.imports) {
// required library
if (importElement.importedLibrary != usedLibrary) {
@@ -126,7 +126,7 @@
CompilationUnit unit = prefixNode.thisOrAncestorOfType<CompilationUnit>();
LibraryElement libraryElement = unit.declaredElement.library;
// prepare used element
- Element usedElement = null;
+ Element usedElement;
if (parent is PrefixedIdentifier) {
PrefixedIdentifier prefixed = parent;
if (prefixed.prefix == prefixNode) {
diff --git a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
index 591896c3..a4bf02d 100644
--- a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
+++ b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
@@ -108,7 +108,7 @@
String directivesCode;
{
StringBuffer sb = StringBuffer();
- _DirectivePriority currentPriority = null;
+ _DirectivePriority currentPriority;
for (_DirectiveInfo directiveInfo in directives) {
if (!hasUnresolvedIdentifierError) {
UriBasedDirective directive = directiveInfo.directive;
diff --git a/pkg/analysis_server/lib/src/services/correction/sort_members.dart b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
index 0065082..a7730c0 100644
--- a/pkg/analysis_server/lib/src/services/correction/sort_members.dart
+++ b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
@@ -102,9 +102,9 @@
void _sortClassMembers(ClassOrMixinDeclaration classDeclaration) {
List<_MemberInfo> members = <_MemberInfo>[];
for (ClassMember member in classDeclaration.members) {
- _MemberKind kind = null;
+ _MemberKind kind;
bool isStatic = false;
- String name = null;
+ String name;
if (member is ConstructorDeclaration) {
kind = _MemberKind.CLASS_CONSTRUCTOR;
SimpleIdentifier nameNode = member.name;
@@ -164,7 +164,7 @@
}
UriBasedDirective uriDirective = directive as UriBasedDirective;
String uriContent = uriDirective.uri.stringValue;
- _DirectivePriority kind = null;
+ _DirectivePriority kind;
if (directive is ImportDirective) {
if (uriContent.startsWith("dart:")) {
kind = _DirectivePriority.IMPORT_SDK;
@@ -228,7 +228,7 @@
{
StringBuffer sb = StringBuffer();
String endOfLine = this.endOfLine;
- _DirectivePriority currentPriority = null;
+ _DirectivePriority currentPriority;
bool firstOutputDirective = true;
for (_DirectiveInfo directive in directives) {
if (currentPriority != directive.priority) {
@@ -272,8 +272,8 @@
void _sortUnitMembers() {
List<_MemberInfo> members = [];
for (CompilationUnitMember member in unit.declarations) {
- _MemberKind kind = null;
- String name = null;
+ _MemberKind kind;
+ String name;
if (member is ClassOrMixinDeclaration) {
kind = _MemberKind.UNIT_CLASS;
name = member.name.name;
diff --git a/pkg/analysis_server/lib/src/services/correction/status.dart b/pkg/analysis_server/lib/src/services/correction/status.dart
index 296f924..9335d77 100644
--- a/pkg/analysis_server/lib/src/services/correction/status.dart
+++ b/pkg/analysis_server/lib/src/services/correction/status.dart
@@ -12,7 +12,7 @@
* The current severity of this [RefactoringStatus] - the maximum of the
* severities of its [entries].
*/
- RefactoringProblemSeverity _severity = null;
+ RefactoringProblemSeverity _severity;
/**
* A list of [RefactoringProblem]s.
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 8b06274..df374c3 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -644,7 +644,7 @@
* declared at [offset].
*/
Set<String> findPossibleLocalVariableConflicts(int offset) {
- Set<String> conflicts = Set<String>();
+ Set<String> conflicts = <String>{};
AstNode enclosingNode = findNode(offset);
Block enclosingBlock = enclosingNode.thisOrAncestorOfType<Block>();
if (enclosingBlock != null) {
@@ -1070,7 +1070,7 @@
bool shouldSkip(ClassMember existingMember)) {
String indent = getIndent(1);
// Find the last target member.
- ClassMember targetMember = null;
+ ClassMember targetMember;
List<ClassMember> members = _getMembers(declaration);
if (members == null) {
return null;
@@ -1417,7 +1417,7 @@
}
class _CollectReferencedUnprefixedNames extends RecursiveAstVisitor {
- final Set<String> names = Set<String>();
+ final Set<String> names = <String>{};
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
diff --git a/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart b/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart
index 35bcdd0..136f0d5 100644
--- a/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart
+++ b/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart
@@ -117,7 +117,7 @@
/// The set of classes for which we are currently adding properties,
/// used to prevent infinite recursion.
- final Set<ClassElement> classesBeingProcessed = Set<ClassElement>();
+ final Set<ClassElement> classesBeingProcessed = <ClassElement>{};
/// The resolved unit with the widget [InstanceCreationExpression].
final ResolvedUnitResult resolvedUnit;
@@ -268,7 +268,7 @@
var classElement = constructorElement.enclosingElement;
if (!classesBeingProcessed.add(classElement)) return;
- var existingNamed = Set<ParameterElement>();
+ var existingNamed = <ParameterElement>{};
if (instanceCreation != null) {
for (var argumentExpression in instanceCreation.argumentList.arguments) {
var parameter = argumentExpression.staticParameterElement;
diff --git a/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart b/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
index 16c228a..d0b4329 100644
--- a/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
+++ b/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
@@ -895,10 +895,10 @@
_handleRefCallEdge(
Element element, {
- SyntacticEntity syntacticEntity = null,
+ SyntacticEntity syntacticEntity,
int start = _notFound,
int end = _notFound,
- KytheVName enclosingTarget = null,
+ KytheVName enclosingTarget,
}) {
if (element is ExecutableElement &&
_enclosingVName != _enclosingFileVName) {
@@ -932,11 +932,11 @@
KytheVName _handleRefEdge(
Element element,
List<String> refEdgeTypes, {
- SyntacticEntity syntacticEntity = null,
+ SyntacticEntity syntacticEntity,
int start = _notFound,
int end = _notFound,
- KytheVName enclosingTarget = null,
- KytheVName enclosingAnchor = null,
+ KytheVName enclosingTarget,
+ KytheVName enclosingAnchor,
}) {
assert(refEdgeTypes.isNotEmpty);
element = _findNonSyntheticElement(element);
@@ -1120,7 +1120,7 @@
/// [KytheEntry] protos.
mixin OutputUtils {
/// A set of [String]s which have already had a name [KytheVName] created.
- final Set<String> nameNodes = Set<String>();
+ final Set<String> nameNodes = <String>{};
String get corpus;
@@ -1152,13 +1152,13 @@
/// Finally, for all anchors, a childof edge with a target of the enclosing
/// file is written out.
KytheVName addAnchorEdgesContainingEdge({
- SyntacticEntity syntacticEntity = null,
+ SyntacticEntity syntacticEntity,
int start = _notFound,
int end = _notFound,
List<String> edges = const [],
- KytheVName target = null,
- KytheVName enclosingTarget = null,
- KytheVName enclosingAnchor = null,
+ KytheVName target,
+ KytheVName enclosingTarget,
+ KytheVName enclosingAnchor,
}) {
if (start == _notFound && end == _notFound) {
if (syntacticEntity != null) {
@@ -1206,7 +1206,7 @@
KytheEntry addEdge(KytheVName source, String edgeKind, KytheVName target,
{int ordinalIntValue = _notFound}) {
if (ordinalIntValue == _notFound) {
- return addEntry(source, edgeKind, target, "/", List<int>());
+ return addEntry(source, edgeKind, target, "/", <int>[]);
} else {
return addEntry(source, edgeKind, target, schema.ORDINAL,
_encodeInt(ordinalIntValue));
@@ -1240,7 +1240,7 @@
Element functionElement,
FormalParameterList paramNodes,
KytheVName functionVName, {
- AstNode returnNode = null,
+ AstNode returnNode,
}) {
var i = 0;
var funcTypeVName =
@@ -1296,10 +1296,10 @@
/// currently guarantee that the inputs to these fact kinds are valid for the
/// associated nodeKind- if a non-null, then it will set.
KytheVName addNodeAndFacts(String nodeKind,
- {Element element = null,
- KytheVName nodeVName = null,
- String subKind = null,
- String completeFact = null}) {
+ {Element element,
+ KytheVName nodeVName,
+ String subKind,
+ String completeFact}) {
nodeVName ??= _vNameFromElement(element, nodeKind);
addFact(nodeVName, schema.NODE_KIND_FACT, _encode(nodeKind));
if (subKind != null) {
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index bc12a90..ca6dce2 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -29,6 +29,7 @@
static const String empty_catches = 'empty_catches';
static const String empty_constructor_bodies = 'empty_constructor_bodies';
static const String empty_statements = 'empty_statements';
+ static const String hash_and_equals = 'hash_and_equals';
static const String no_duplicate_case_values = 'no_duplicate_case_values';
static const String non_constant_identifier_names =
'non_constant_identifier_names';
@@ -51,13 +52,14 @@
'prefer_for_elements_to_map_fromIterable';
static const String prefer_generic_function_type_aliases =
'prefer_generic_function_type_aliases';
- static const String prefer_inlined_adds = 'prefer_inlined_adds';
- static const String prefer_int_literals = 'prefer_int_literals';
static const String prefer_if_elements_to_conditional_expressions =
'prefer_if_elements_to_conditional_expressions';
+ static const String prefer_if_null_operators = 'prefer_if_null_operators';
+ static const String prefer_inlined_adds = 'prefer_inlined_adds';
+ static const String prefer_int_literals = 'prefer_int_literals';
static const String prefer_is_empty = 'prefer_is_empty';
static const String prefer_is_not_empty = 'prefer_is_not_empty';
- static const String prefer_if_null_operators = 'prefer_if_null_operators';
+ static const String prefer_iterable_whereType = 'prefer_iterable_whereType';
static const String prefer_null_aware_operators =
'prefer_null_aware_operators';
static const String prefer_relative_imports = 'prefer_relative_imports';
@@ -73,7 +75,11 @@
static const String unnecessary_const = 'unnecessary_const';
static const String unnecessary_lambdas = 'unnecessary_lambdas';
static const String unnecessary_new = 'unnecessary_new';
+ static const String unnecessary_null_in_if_null_operators =
+ 'unnecessary_null_in_if_null_operators';
static const String unnecessary_overrides = 'unnecessary_overrides';
static const String unnecessary_this = 'unnecessary_this';
+ static const String use_function_type_syntax_for_parameters =
+ 'use_function_type_syntax_for_parameters';
static const String use_rethrow_when_possible = 'use_rethrow_when_possible';
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
index 846b0b6..baed2ce 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
@@ -91,7 +91,7 @@
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
// prepare "get" keyword
- Token getKeyword = null;
+ Token getKeyword;
{
var sessionHelper = AnalysisSessionHelper(session);
var result = await sessionHelper.getElementDeclaration(element);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index 4006115..2c77a76 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -56,7 +56,7 @@
String stringLiteralPart;
final List<SourceRange> occurrences = <SourceRange>[];
final Map<Element, int> elementIds = <Element, int>{};
- Set<String> excludedVariableNames = Set<String>();
+ Set<String> excludedVariableNames = <String>{};
ExtractLocalRefactoringImpl(
this.resolveResult, this.selectionOffset, this.selectionLength) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index a13e65e..c58b0a3 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -81,7 +81,7 @@
final int selectionLength;
SourceRange selectionRange;
CorrectionUtils utils;
- final Set<Source> librariesToImport = Set<Source>();
+ final Set<Source> librariesToImport = <Source>{};
@override
String returnType = '';
@@ -112,9 +112,9 @@
/**
* The set of names that are referenced without any qualifier.
*/
- final Set<String> _unqualifiedNames = Set<String>();
+ final Set<String> _unqualifiedNames = <String>{};
- final Set<String> _excludedNames = Set<String>();
+ final Set<String> _excludedNames = <String>{};
List<RefactoringMethodParameter> _parameters = <RefactoringMethodParameter>[];
final Map<String, RefactoringMethodParameter> _parametersMap =
<String, RefactoringMethodParameter>{};
@@ -334,7 +334,7 @@
}
}
// prepare declaration source
- String declarationSource = null;
+ String declarationSource;
{
String returnExpressionSource = _getMethodBodySource();
// closure
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
index d16c157..4b42d3f 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
@@ -335,7 +335,7 @@
}
// Collect used public names.
- var usedNames = Set<String>();
+ var usedNames = <String>{};
for (var parameter in _parameters) {
if (!parameter.name.startsWith('_')) {
usedNames.add(parameter.name);
@@ -598,7 +598,7 @@
final SourceRange expressionRange;
final RefactoringStatus status = RefactoringStatus();
- final Set<Element> uniqueElements = Set<Element>();
+ final Set<Element> uniqueElements = <Element>{};
final List<_Parameter> parameters = [];
List<ClassElement> enclosingClasses;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index 7f45de8..e77eee7 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -57,7 +57,7 @@
part._parameters.forEach(
(ParameterElement parameter, List<_ParameterOccurrence> occurrences) {
// prepare argument
- Expression argument = null;
+ Expression argument;
for (Expression arg in arguments) {
if (arg.staticParameterElement == parameter) {
argument = arg;
@@ -150,7 +150,7 @@
* at [node].
*/
Set<String> _getNamesConflictingAt(AstNode node) {
- Set<String> result = Set<String>();
+ Set<String> result = <String>{};
// local variables and functions
{
SourceRange localsRange = _getLocalsConflictingRange(node);
@@ -166,7 +166,7 @@
{
ClassElement enclosingClassElement = getEnclosingClassElement(node);
if (enclosingClassElement != null) {
- Set<ClassElement> elements = Set<ClassElement>();
+ Set<ClassElement> elements = <ClassElement>{};
elements.add(enclosingClassElement);
elements.addAll(getSuperClasses(enclosingClassElement));
for (ClassElement classElement in elements) {
@@ -208,7 +208,7 @@
_SourcePart _methodExpressionPart;
_SourcePart _methodStatementsPart;
final List<_ReferenceProcessor> _referenceProcessors = [];
- final Set<Element> _alreadyMadeAsync = Set<Element>();
+ final Set<Element> _alreadyMadeAsync = <Element>{};
InlineMethodRefactoringImpl(
this.searchEngine, this.resolveResult, this.offset)
@@ -608,7 +608,7 @@
// PropertyAccessorElement
if (ref._methodElement is PropertyAccessorElement) {
Expression usage = _node;
- Expression target = null;
+ Expression target;
bool cascade = false;
if (nodeParent is PrefixedIdentifier) {
PrefixedIdentifier propertyAccess = nodeParent;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index 5bf14cb..11beace 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -147,7 +147,7 @@
final bool isRename;
final RefactoringStatus result = RefactoringStatus();
- Set<Element> elements = Set<Element>();
+ Set<Element> elements = <Element>{};
List<SearchMatch> references = <SearchMatch>[];
_ClassMemberValidator.forCreate(
@@ -307,7 +307,7 @@
if (element is ClassMemberElement) {
elements = await getHierarchyMembers(searchEngine, element);
} else {
- elements = Set.from([element]);
+ elements = {element};
}
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 1e7a01a..80f05cd 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -56,7 +56,7 @@
// update declaration
{
PrefixElement prefix = element.prefix;
- SourceEdit edit = null;
+ SourceEdit edit;
if (newName.isEmpty) {
ImportDirective node = _findNode();
int uriEnd = node.uri.end;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
index 0d06dbd..2d3c138 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
@@ -112,7 +112,7 @@
final String newName;
final LocalElement target;
final Map<Element, SourceRange> visibleRangeMap;
- final Set<Element> conflictingLocals = Set<Element>();
+ final Set<Element> conflictingLocals = <Element>{};
_ConflictValidatorVisitor(
this.result,
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index 0931c5a..5deff3b 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -184,7 +184,7 @@
Set<ClassElement> getSuperClasses(ClassElement seed) {
Set<ClassElement> result = HashSet<ClassElement>();
// prepare queue
- List<ClassElement> queue = List<ClassElement>();
+ List<ClassElement> queue = <ClassElement>[];
queue.add(seed);
// process queue
while (queue.isNotEmpty) {
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 3390b97..74af165 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -27,8 +27,8 @@
String libraryUriStr = type.librarySource.uri.toString();
bool hasSubtypes = false;
- Set<String> visitedIds = Set<String>();
- Set<String> members = Set<String>();
+ Set<String> visitedIds = <String>{};
+ Set<String> members = <String>{};
Future<void> addMembers(ClassElement type, SubtypeResult subtype) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
@@ -61,7 +61,7 @@
Future<Set<ClassElement>> searchAllSubtypes(ClassElement type) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
- Set<ClassElement> allSubtypes = Set<ClassElement>();
+ Set<ClassElement> allSubtypes = <ClassElement>{};
Future<void> addSubtypes(ClassElement type) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
@@ -134,7 +134,7 @@
Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
- Set<Element> allElements = Set<Element>();
+ Set<Element> allElements = <Element>{};
RegExp regExp = RegExp(pattern);
List<AnalysisDriver> drivers = _drivers.toList();
for (AnalysisDriver driver in drivers) {
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index a879b47..e52b7b0 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -20,6 +20,7 @@
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:linter/src/rules.dart';
+import 'package:meta/meta.dart';
import 'src/utilities/mock_packages.dart';
@@ -27,7 +28,7 @@
* Finds an [Element] with the given [name].
*/
Element findChildElement(Element root, String name, [ElementKind kind]) {
- Element result = null;
+ Element result;
root.accept(_ElementVisitorFunctionWrapper((Element element) {
if (element.name != name) {
return;
@@ -182,6 +183,7 @@
return resolveResult.unit;
}
+ @mustCallSuper
void setUp() {
registerLintRules();
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index c13e5bf..d4fee97 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
+import 'dart:convert';
import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
@@ -637,6 +638,30 @@
expect(hover, isNull);
}
+ test_nonNullable() async {
+ createAnalysisOptionsFile(experiments: ['non-nullable']);
+ addTestFile('''
+int? f(double? a) => null;
+
+main() {
+ f(null);
+}
+''');
+ var hover = await prepareHover('f(null)');
+ _assertJsonText(hover, r'''
+{
+ "offset": 39,
+ "length": 1,
+ "containingLibraryPath": "/project/bin/test.dart",
+ "containingLibraryName": "bin/test.dart",
+ "elementDescription": "int? f(double? a)",
+ "elementKind": "function",
+ "isDeprecated": false,
+ "staticType": "int? Function(double?)"
+}
+''');
+ }
+
test_parameter_declaration_fieldFormal() async {
addTestFile('''
class A {
@@ -702,4 +727,15 @@
expect(hover.elementKind, 'parameter');
expect(hover.staticType, 'int');
}
+
+ void _assertJsonText(Object object, String expected) {
+ expected = expected.trimRight();
+ var actual = JsonEncoder.withIndent(' ').convert(object);
+ if (actual != expected) {
+ print('-----');
+ print(actual);
+ print('-----');
+ }
+ expect(actual, expected);
+ }
}
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index c4e462d..56bba4d 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -36,7 +36,7 @@
*/
Future do_not_test_no_duplicate_notifications() async {
// Subscribe to STATUS so we'll know when analysis is done.
- server.serverServices = [ServerService.STATUS].toSet();
+ server.serverServices = {ServerService.STATUS};
newFolder('/foo');
newFolder('/bar');
newFile('/foo/foo.dart', content: 'import "../bar/bar.dart";');
@@ -45,7 +45,7 @@
Map<AnalysisService, Set<String>> subscriptions =
<AnalysisService, Set<String>>{};
for (AnalysisService service in AnalysisService.VALUES) {
- subscriptions[service] = <String>[bar.path].toSet();
+ subscriptions[service] = <String>{bar.path};
}
// The following line causes the isolate to continue running even though the
// test completes.
@@ -58,7 +58,7 @@
await server.onAnalysisComplete;
expect(server.statusAnalyzing, isFalse);
expect(channel.notificationsReceived, isNotEmpty);
- Set<String> notificationTypesReceived = Set<String>();
+ Set<String> notificationTypesReceived = <String>{};
for (Notification notification in channel.notificationsReceived) {
String notificationType = notification.event;
switch (notificationType) {
@@ -139,7 +139,7 @@
''');
server.setAnalysisRoots('0', [convertPath('/project')], [], {});
server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
- AnalysisService.NAVIGATION: Set<String>.from([path])
+ AnalysisService.NAVIGATION: <String>{path}
});
// We respect subscriptions, even for excluded files.
@@ -159,7 +159,7 @@
''');
server.setAnalysisRoots('0', [convertPath('/project')], [], {});
server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
- AnalysisService.NAVIGATION: Set<String>.from([path])
+ AnalysisService.NAVIGATION: <String>{path}
});
// We respect subscriptions, even for excluded files.
diff --git a/pkg/analysis_server/test/channel/byte_stream_channel_test.dart b/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
index b49a2fd..9050f25 100644
--- a/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
+++ b/pkg/analysis_server/test/channel/byte_stream_channel_test.dart
@@ -265,7 +265,7 @@
Encoding encoding;
@override
- Future done = null;
+ Future done;
@override
void add(List<int> data) {}
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index afcc4cb..895a345 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -1645,7 +1645,7 @@
TestContextManagerCallbacks callbacks;
- String projPath = null;
+ String projPath;
AnalysisError missing_return =
AnalysisError(null, 0, 1, HintCode.MISSING_RETURN, [
diff --git a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
index 5fd6acf..f665ff1 100644
--- a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
@@ -69,9 +69,9 @@
List<String> staticTypeRegexps, {
bool isLocal = false,
bool isCore = false,
- String docRegexp = null,
+ String docRegexp,
bool isLiteral = false,
- List<String> parameterRegexps = null,
+ List<String> parameterRegexps,
}) {
int offset = text.indexOf(target);
return sendAnalysisGetHover(pathname, offset).then((result) async {
diff --git a/pkg/analysis_server/test/integration/analysis/highlights2_test.dart b/pkg/analysis_server/test/integration/analysis/highlights2_test.dart
index dbfdde6..9967f27 100644
--- a/pkg/analysis_server/test/integration/analysis/highlights2_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/highlights2_test.dart
@@ -42,7 +42,7 @@
String highlightedText = text.substring(startIndex, endIndex);
HighlightRegionType type = region.type;
if (!highlights.containsKey(type)) {
- highlights[type] = Set<String>();
+ highlights[type] = <String>{};
}
highlights[type].add(highlightedText);
}
diff --git a/pkg/analysis_server/test/integration/analysis/highlights_test.dart b/pkg/analysis_server/test/integration/analysis/highlights_test.dart
index 511c27b..375cf79 100644
--- a/pkg/analysis_server/test/integration/analysis/highlights_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/highlights_test.dart
@@ -40,7 +40,7 @@
String highlightedText = text.substring(startIndex, endIndex);
HighlightRegionType type = region.type;
if (!highlights.containsKey(type)) {
- highlights[type] = Set<String>();
+ highlights[type] = <String>{};
}
highlights[type].add(highlightedText);
}
diff --git a/pkg/analysis_server/test/integration/analysis/overrides_test.dart b/pkg/analysis_server/test/integration/analysis/overrides_test.dart
index c21b798..9505e02b 100644
--- a/pkg/analysis_server/test/integration/analysis/overrides_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/overrides_test.dart
@@ -95,7 +95,7 @@
List<OverriddenMember> interfaceMembers = override.interfaceMembers;
if (expectedOverridesInterfaces.isNotEmpty) {
expect(interfaceMembers, isNotNull);
- Set<String> actualOverridesInterfaces = Set<String>();
+ Set<String> actualOverridesInterfaces = <String>{};
for (OverriddenMember overriddenMember in interfaceMembers) {
expect(overriddenMember.element.name, equals(methodName));
String className = overriddenMember.className;
diff --git a/pkg/analysis_server/test/integration/lsp_server/analyzer_status_test.dart b/pkg/analysis_server/test/integration/lsp_server/analyzer_status_test.dart
index bff7062..d597d84 100644
--- a/pkg/analysis_server/test/integration/lsp_server/analyzer_status_test.dart
+++ b/pkg/analysis_server/test/integration/lsp_server/analyzer_status_test.dart
@@ -22,7 +22,7 @@
// To avoid races, set up listeners for the notifications before we initialise
// and track which event came first to ensure they arrived in the expected
// order.
- bool firstNotificationWasAnalyzing = null;
+ bool firstNotificationWasAnalyzing;
final startNotification = waitForAnalysisStart()
.then((_) => firstNotificationWasAnalyzing ??= true);
final completeNotification = waitForAnalysisComplete()
diff --git a/pkg/analysis_server/test/integration/support/integration_tests.dart b/pkg/analysis_server/test/integration/support/integration_tests.dart
index a7b0193..c5beb46 100644
--- a/pkg/analysis_server/test/integration/support/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/support/integration_tests.dart
@@ -488,7 +488,7 @@
/**
* Stopwatch that we use to generate timing information for debug output.
*/
- Stopwatch _time = Stopwatch();
+ final Stopwatch _time = Stopwatch();
/**
* The [currentElapseTime] at which the last communication was received from the server
diff --git a/pkg/analysis_server/test/lsp/analyzer_status_test.dart b/pkg/analysis_server/test/lsp/analyzer_status_test.dart
index 1f5859c..4ddd08f 100644
--- a/pkg/analysis_server/test/lsp/analyzer_status_test.dart
+++ b/pkg/analysis_server/test/lsp/analyzer_status_test.dart
@@ -22,7 +22,7 @@
// To avoid races, set up listeners for the notifications before we initialise
// and track which event came first to ensure they arrived in the expected
// order.
- bool firstNotificationWasAnalyzing = null;
+ bool firstNotificationWasAnalyzing;
final startNotification = waitForAnalysisStart()
.then((_) => firstNotificationWasAnalyzing ??= true);
final completeNotification = waitForAnalysisComplete()
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart
index c30d692..8ff865f 100644
--- a/pkg/analysis_server/test/lsp/diagnostic_test.dart
+++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -87,7 +87,7 @@
newFile(dotFolderFilePath, content: 'String a = 1;');
- List<Diagnostic> diagnostics = null;
+ List<Diagnostic> diagnostics;
waitForDiagnostics(dotFolderFileUri).then((d) => diagnostics = d);
// Send a request for a hover.
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index f029b61..348afa7 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -203,34 +203,34 @@
class MockSource extends StringTypedMock implements Source {
@override
- TimestampedData<String> contents = null;
+ TimestampedData<String> contents;
@override
- String encoding = null;
+ String encoding;
@override
- String fullName = null;
+ String fullName;
@override
- bool isInSystemLibrary = null;
+ bool isInSystemLibrary;
@override
- Source librarySource = null;
+ Source librarySource;
@override
- int modificationStamp = null;
+ int modificationStamp;
@override
- String shortName = null;
+ String shortName;
@override
- Source source = null;
+ Source source;
@override
- Uri uri = null;
+ Uri uri;
@override
- UriKind uriKind = null;
+ UriKind uriKind;
MockSource([String name = 'mocked.dart']) : super(name);
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index b855259..627a3d3 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -302,7 +302,7 @@
String message;
@override
- String correction = null;
+ String correction;
@override
int length;
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index b8ebe4e..d1e5ff2 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -80,7 +80,7 @@
List<int> requiredParamIndices = const <int>[],
bool includeColon = true,
bool includeComma = false}) {
- List<CompletionSuggestion> expected = List<CompletionSuggestion>();
+ List<CompletionSuggestion> expected = <CompletionSuggestion>[];
int paramIndex = 0;
namedArgumentsWithTypes.forEach((String name, String type) {
String completion = includeColon ? '$name: ' : name;
@@ -106,7 +106,7 @@
* Assert that the specified suggestions are the only suggestions.
*/
void assertSuggestions(List<String> suggestions) {
- List<CompletionSuggestion> expected = List<CompletionSuggestion>();
+ List<CompletionSuggestion> expected = <CompletionSuggestion>[];
for (String suggestion in suggestions) {
// Selection offset should be before any trailing commas.
int selectionOffset =
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index a42d116..25ba5d3 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -8,9 +8,10 @@
import 'package:analysis_server/src/services/completion/completion_core.dart';
import 'package:analysis_server/src/services/completion/completion_performance.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'
- show DartCompletionRequestImpl;
+ show DartCompletionManager, DartCompletionRequestImpl;
import 'package:analyzer/src/generated/parser.dart' as analyzer;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:meta/meta.dart';
import 'package:test/test.dart';
import '../../../abstract_context.dart';
@@ -21,16 +22,58 @@
return c1.compareTo(c2);
}
-abstract class DartCompletionContributorTest extends AbstractContextTest {
+/// Base class for tests that validate individual [DartCompletionContributor]
+/// suggestions.
+abstract class DartCompletionContributorTest
+ extends _BaseDartCompletionContributorTest {
+ DartCompletionContributor contributor;
+
+ @nonVirtual
+ @override
+ Future<List<CompletionSuggestion>> computeContributedSuggestions(
+ DartCompletionRequest request) async {
+ return contributor.computeSuggestions(request);
+ }
+
+ DartCompletionContributor createContributor();
+
+ @override
+ void setUp() {
+ super.setUp();
+ contributor = createContributor();
+ }
+}
+
+/// Base class for tests that validate [DartCompletionManager] suggestions.
+class DartCompletionManagerTest extends _BaseDartCompletionContributorTest {
+ DartCompletionManager completionManager;
+
+ @nonVirtual
+ @override
+ Future<List<CompletionSuggestion>> computeContributedSuggestions(
+ DartCompletionRequest request) async {
+ final baseRequest = CompletionRequestImpl(
+ request.result, completionOffset, CompletionPerformance());
+ return completionManager.computeSuggestions(baseRequest);
+ }
+
+ @override
+ setUp() {
+ super.setUp();
+ completionManager = DartCompletionManager();
+ }
+}
+
+abstract class _BaseDartCompletionContributorTest extends AbstractContextTest {
static const String _UNCHECKED = '__UNCHECKED__';
String testFile;
int completionOffset;
int replacementOffset;
int replacementLength;
- DartCompletionContributor contributor;
- DartCompletionRequest request;
- List<CompletionSuggestion> suggestions;
+ DartCompletionRequest request;
+
+ List<CompletionSuggestion> suggestions;
/**
* If `true` and `null` is specified as the suggestion's expected returnType
* then the actual suggestion is expected to have a `dynamic` returnType.
@@ -75,7 +118,7 @@
expect(suggestion.hasNamedParameters, isNotNull);
}
- void assertNoSuggestions({CompletionSuggestionKind kind = null}) {
+ void assertNoSuggestions({CompletionSuggestionKind kind}) {
if (kind == null) {
if (suggestions.isNotEmpty) {
failedCompletion('Expected no suggestions', suggestions);
@@ -102,7 +145,7 @@
CompletionSuggestion assertSuggest(String completion,
{CompletionSuggestionKind csKind = CompletionSuggestionKind.INVOCATION,
int relevance = DART_RELEVANCE_DEFAULT,
- ElementKind elemKind = null,
+ ElementKind elemKind,
bool isDeprecated = false,
bool isPotential = false,
String elemFile,
@@ -461,6 +504,9 @@
return cs;
}
+ Future<List<CompletionSuggestion>> computeContributedSuggestions(
+ DartCompletionRequest request);
+
Future computeSuggestions({int times = 200}) async {
var resolveResult = await session.getResolvedUnit(testFile);
CompletionRequestImpl baseRequest = CompletionRequestImpl(
@@ -474,12 +520,10 @@
replacementLength = range.length;
// Request completions
- suggestions = await contributor.computeSuggestions(request);
+ suggestions = await computeContributedSuggestions(request);
expect(suggestions, isNotNull, reason: 'expected suggestions');
}
- DartCompletionContributor createContributor();
-
void failedCompletion(String message,
[Iterable<CompletionSuggestion> completions]) {
StringBuffer sb = StringBuffer(message);
@@ -495,9 +539,9 @@
}
CompletionSuggestion getSuggest(
- {String completion = null,
- CompletionSuggestionKind csKind = null,
- ElementKind elemKind = null}) {
+ {String completion,
+ CompletionSuggestionKind csKind,
+ ElementKind elemKind}) {
CompletionSuggestion cs;
if (suggestions != null) {
suggestions.forEach((CompletionSuggestion s) {
@@ -546,6 +590,5 @@
void setUp() {
super.setUp();
testFile = convertPath('/home/test/lib/test.dart');
- contributor = createContributor();
}
}
diff --git a/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
index c4d1a54..71142b0 100644
--- a/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
@@ -144,6 +144,24 @@
test_literal_doesNotMatch() async {
addTestSource('''
+extension E on String {
+ bool a(int b, int c) {}
+ int get b => 0;
+ set c(int d) {}
+}
+
+void f() {
+ 0.^
+}
+''');
+ await computeSuggestions();
+ assertNotSuggested('a');
+ assertNotSuggested('b');
+ assertNotSuggested('c');
+ }
+
+ test_literal_doesNotMatch_generic() async {
+ addTestSource('''
extension E<T extends num> on List<T> {
bool a(int b, int c) {}
int get b => 0;
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 c06ca93..9a53e8d 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
@@ -28,7 +28,6 @@
Keyword.FALSE,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.NULL,
Keyword.TRUE,
];
@@ -38,7 +37,6 @@
static const List<Keyword> EXPRESSION_START_INSTANCE = [
Keyword.CONST,
Keyword.FALSE,
- Keyword.NEW,
Keyword.NULL,
Keyword.SUPER,
Keyword.THIS,
@@ -48,7 +46,6 @@
static const List<Keyword> EXPRESSION_START_NO_INSTANCE = [
Keyword.CONST,
Keyword.FALSE,
- Keyword.NEW,
Keyword.NULL,
Keyword.TRUE,
];
@@ -174,7 +171,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.SWITCH,
@@ -201,7 +197,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.SWITCH,
@@ -228,7 +223,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
@@ -252,7 +246,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.THIS,
@@ -278,7 +271,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
@@ -304,7 +296,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SUPER,
Keyword.SWITCH,
@@ -332,7 +323,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
@@ -355,7 +345,6 @@
Keyword.FINAL,
Keyword.FOR,
Keyword.IF,
- Keyword.NEW,
Keyword.RETURN,
Keyword.SWITCH,
Keyword.THROW,
@@ -381,9 +370,9 @@
void assertSuggestKeywords(Iterable<Keyword> expectedKeywords,
{List<String> pseudoKeywords = NO_PSEUDO_KEYWORDS,
int relevance = DART_RELEVANCE_KEYWORD}) {
- Set<String> expectedCompletions = Set<String>();
+ Set<String> expectedCompletions = <String>{};
Map<String, int> expectedOffsets = <String, int>{};
- Set<String> actualCompletions = Set<String>();
+ Set<String> actualCompletions = <String>{};
expectedCompletions.addAll(expectedKeywords.map((keyword) {
String text = keyword.lexeme;
if (['import', 'export', 'part'].contains(text)) {
diff --git a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
index 93380d8..6cdf195 100644
--- a/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/override_contributor_test.dart
@@ -37,6 +37,45 @@
_assertNoOverrideContaining('bar');
}
+ test_customOperator() async {
+ addTestSource('''
+class A {
+ void operator &(A other) { }
+}
+class B extends A {
+ other^
+}
+''');
+ await computeSuggestions();
+ _assertOverride('''
+@override
+ void operator &(A other) {
+ // TODO: implement &
+ super & other;
+ }''',
+ displayText: '&(A other) { … }',
+ selectionOffset: 68,
+ selectionLength: 14);
+ }
+
+ test_equalsOperator() async {
+ addTestSource('''
+class A {
+ other^
+}
+''');
+ await computeSuggestions();
+ _assertOverride('''
+@override
+ bool operator ==(Object other) {
+ // TODO: implement ==
+ return super == other;
+ }''',
+ displayText: '==(Object other) { … }',
+ selectionOffset: 75,
+ selectionLength: 22);
+ }
+
test_fromMultipleSuperclasses() async {
addTestSource(r'''
class A {
diff --git a/pkg/analysis_server/test/services/correction/name_suggestion_test.dart b/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
index d8c4fd5..3f50c49 100644
--- a/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
+++ b/pkg/analysis_server/test/services/correction/name_suggestion_test.dart
@@ -25,7 +25,7 @@
var res = sortedNodes as String;
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
var expr = findNodeAtString('as String', (node) => node is AsExpression);
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
unorderedEquals(['sortedNodes', 'nodes']));
@@ -38,7 +38,7 @@
TreeNode node = null;
}
''');
- Set<String> excluded = Set<String>.from([]);
+ Set<String> excluded = <String>{};
DartType expectedType = findLocalVariable('node').type;
Expression assignedExpression =
findNodeAtString('null;', (node) => node is NullLiteral);
@@ -58,12 +58,12 @@
// first choice for "double" is "d"
expect(
getVariableNameSuggestionsForExpression(
- expectedType, assignedExpression, Set.from([])),
+ expectedType, assignedExpression, {}),
unorderedEquals(['d']));
// if "d" is used, try "e", "f", etc
expect(
getVariableNameSuggestionsForExpression(
- expectedType, assignedExpression, Set.from(['d', 'e'])),
+ expectedType, assignedExpression, {'d', 'e'}),
unorderedEquals(['f']));
}
@@ -78,12 +78,12 @@
// first choice for "int" is "i"
expect(
getVariableNameSuggestionsForExpression(
- expectedType, assignedExpression, Set.from([])),
+ expectedType, assignedExpression, {}),
unorderedEquals(['i']));
// if "i" is used, try "j", "k", etc
expect(
getVariableNameSuggestionsForExpression(
- expectedType, assignedExpression, Set.from(['i', 'j'])),
+ expectedType, assignedExpression, {'i', 'j'}),
unorderedEquals(['k']));
}
@@ -98,7 +98,7 @@
// first choice for "String" is "s"
expect(
getVariableNameSuggestionsForExpression(
- expectedType, assignedExpression, Set.from([])),
+ expectedType, assignedExpression, {}),
unorderedEquals(['s']));
}
@@ -110,7 +110,7 @@
}
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
var expr = findNodeAtString('new List');
expect(
getVariableNameSuggestionsForExpression(null, expr, excluded,
@@ -129,7 +129,7 @@
print(topNodes[0]);
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
var expr = findNodeAtString('topNodes[0]').parent;
var names = getVariableNameSuggestionsForExpression(null, expr, excluded);
expect(names, unorderedEquals(['topNode', 'node', 'object']));
@@ -145,7 +145,7 @@
new NoSuchClass.named();
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
expect(
getVariableNameSuggestionsForExpression(
null, findNodeAtString('new NoSuchClass()'), excluded),
@@ -171,7 +171,7 @@
foo(a: 111, c: 333, b: 222);
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
{
var expr = findNodeAtString('111');
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
@@ -196,7 +196,7 @@
foo(111, 222, 333);
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
{
var expr = findNodeAtString('111');
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
@@ -221,7 +221,7 @@
foo(111, 222);
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
{
var expr = findNodeAtString('111');
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
@@ -240,7 +240,7 @@
var res = p.getSortedNodes();
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
var expr = findNodeAtString('p.get', (node) => node is MethodInvocation);
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
unorderedEquals(['sortedNodes', 'nodes']));
@@ -252,7 +252,7 @@
var res = p.sortedNodes();
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
var expr = findNodeAtString('p.sorted', (node) => node is MethodInvocation);
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
unorderedEquals(['sortedNodes', 'nodes']));
@@ -264,7 +264,7 @@
var res = p.get();
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
var expr = findNodeAtString('p.get', (node) => node is MethodInvocation);
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
unorderedEquals([]));
@@ -276,7 +276,7 @@
var res = p.sortedNodes;
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
expect(
getVariableNameSuggestionsForExpression(
null,
@@ -292,7 +292,7 @@
p._computeSuffix();
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
expect(
getVariableNameSuggestionsForExpression(
null,
@@ -313,7 +313,7 @@
var res = p.q.sortedNodes;
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
PropertyAccess expression =
findNodeAtString('p.q.sorted', (node) => node is PropertyAccess);
expect(getVariableNameSuggestionsForExpression(null, expression, excluded),
@@ -327,7 +327,7 @@
var res = sortedNodes;
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
var expr = findNodeAtString('sortedNodes;');
expect(getVariableNameSuggestionsForExpression(null, expr, excluded),
unorderedEquals(['sortedNodes', 'nodes']));
@@ -340,7 +340,7 @@
var res = getSortedNodes();
}
''');
- var excluded = Set<String>.from([]);
+ var excluded = <String>{};
expect(
getVariableNameSuggestionsForExpression(
null,
@@ -352,14 +352,14 @@
void test_forText() {
{
- Set<String> excluded = Set<String>.from([]);
+ Set<String> excluded = <String>{};
List<String> suggestions =
getVariableNameSuggestionsForText('Goodbye, cruel world!', excluded);
expect(suggestions,
unorderedEquals(['goodbyeCruelWorld', 'cruelWorld', 'world']));
}
{
- Set<String> excluded = Set<String>.from(['world']);
+ Set<String> excluded = <String>{'world'};
List<String> suggestions =
getVariableNameSuggestionsForText('Goodbye, cruel world!', excluded);
expect(suggestions,
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
index 1a16fef..61b96c0 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
@@ -23,7 +23,7 @@
* of the given [searches].
*/
void assertPotentialEdits(List<String> searches) {
- Set<int> expectedOffsets = Set<int>();
+ Set<int> expectedOffsets = <int>{};
for (String search in searches) {
int offset = findOffset(search);
expectedOffsets.add(offset);
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 297fdf6..5515b02 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
@@ -10,8 +10,8 @@
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'nnbd_migration_test_base.dart';
import '../../../analysis_abstract.dart';
+import 'nnbd_migration_test_base.dart';
main() {
defineReflectiveSuite(() {
@@ -598,6 +598,45 @@
assertDetail(detail: regions[2].details[0], offset: 90, length: 1);
}
+ test_listConstructor_length() async {
+ UnitInfo unit = await buildInfoForSingleTestFile('''
+void f() {
+ List<int> list = List<int>(10);
+}
+''', migratedContent: '''
+void f() {
+ List<int?> list = List<int?>(10);
+}
+''');
+ List<RegionInfo> regions = unit.regions;
+ expect(regions, hasLength(2));
+ // regions[0] is `num? a`.
+ assertRegion(region: regions[1], offset: 39, details: [
+ "List value type must be nullable because a length is specified,"
+ " and the list items are initialized as null."
+ ]);
+ }
+
+ @FailingTest(issue: "https://github.com/dart-lang/sdk/issues/40064")
+ test_listConstructor_length_implicitType() async {
+ UnitInfo unit = await buildInfoForSingleTestFile('''
+void f() {
+ List<int> list = List(10);
+}
+''', migratedContent: '''
+void f() {
+ List<int?> list = List(10);
+}
+''');
+ List<RegionInfo> regions = unit.regions;
+ expect(regions, hasLength(2));
+ // regions[0] is `num? a`.
+ assertRegion(region: regions[1], offset: 40, details: [
+ "List value type must be nullable because a length is specified,"
+ " and the list items are initialized as null."
+ ]);
+ }
+
test_listLiteralTypeArgument_collectionIf() async {
UnitInfo unit = await buildInfoForSingleTestFile('''
void f() {
diff --git a/pkg/analysis_server/test/src/plugin/notification_manager_test.dart b/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
index bee200f..57035e8 100644
--- a/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
+++ b/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
@@ -62,7 +62,7 @@
void test_handlePluginNotification_folding() {
manager.setSubscriptions({
- server.AnalysisService.FOLDING: Set.from([fileA, fileB])
+ server.AnalysisService.FOLDING: {fileA, fileB}
});
FoldingRegion region1 = foldingRegion(10, 3);
FoldingRegion region2 = foldingRegion(20, 6);
@@ -74,7 +74,7 @@
void test_handlePluginNotification_highlights() {
manager.setSubscriptions({
- server.AnalysisService.HIGHLIGHTS: Set.from([fileA, fileB])
+ server.AnalysisService.HIGHLIGHTS: {fileA, fileB}
});
HighlightRegion region1 = highlightRegion(10, 3);
HighlightRegion region2 = highlightRegion(20, 6);
@@ -86,7 +86,7 @@
void test_handlePluginNotification_naviation() {
manager.setSubscriptions({
- server.AnalysisService.NAVIGATION: Set.from([fileA, fileB])
+ server.AnalysisService.NAVIGATION: {fileA, fileB}
});
plugin.AnalysisNavigationParams pluginParams =
pluginNavigationParams(0, 0, file: fileA);
@@ -99,7 +99,7 @@
void test_handlePluginNotification_occurences() {
manager.setSubscriptions({
- server.AnalysisService.OCCURRENCES: Set.from([fileA, fileB])
+ server.AnalysisService.OCCURRENCES: {fileA, fileB}
});
Occurrences occurrences1 = occurrences(0, 0);
Occurrences occurrences2 = occurrences(5, 7);
@@ -112,7 +112,7 @@
void test_handlePluginNotification_outline() {
manager.setSubscriptions({
- server.AnalysisService.OUTLINE: Set.from([fileA, fileB])
+ server.AnalysisService.OUTLINE: {fileA, fileB}
});
Outline outline1 = outline(0, 0);
plugin.AnalysisOutlineParams params =
@@ -177,7 +177,7 @@
void test_recordFoldingRegions_withSubscription() {
manager.setSubscriptions({
- server.AnalysisService.FOLDING: Set.from([fileA, fileB])
+ server.AnalysisService.FOLDING: {fileA, fileB}
});
//
// Regions should be reported when they are recorded.
@@ -216,7 +216,7 @@
void test_recordHighlightRegions_withSubscription() {
manager.setSubscriptions({
- server.AnalysisService.HIGHLIGHTS: Set.from([fileA, fileB])
+ server.AnalysisService.HIGHLIGHTS: {fileA, fileB}
});
//
// Regions should be reported when they are recorded.
@@ -256,7 +256,7 @@
void test_recordNavigationParams_withSubscription() {
manager.setSubscriptions({
- server.AnalysisService.NAVIGATION: Set.from([fileA, fileB])
+ server.AnalysisService.NAVIGATION: {fileA, fileB}
});
//
// Parameters should be reported when they are recorded.
@@ -324,7 +324,7 @@
void test_recordOccurrences_withSubscription() {
manager.setSubscriptions({
- server.AnalysisService.OCCURRENCES: Set.from([fileA, fileB])
+ server.AnalysisService.OCCURRENCES: {fileA, fileB}
});
//
// Occurrences should be reported when they are recorded.
@@ -367,7 +367,7 @@
// TODO(brianwilkerson) Figure out outlines. What should we do when merge
// cannot produce a single outline?
manager.setSubscriptions({
- server.AnalysisService.OUTLINE: Set.from([fileA, fileB])
+ server.AnalysisService.OUTLINE: {fileA, fileB}
});
//
// Outlines should be reported when they are recorded.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
index 13a2b32..8c615c2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
@@ -11,12 +11,13 @@
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(ConvertToGenericFunctionSyntaxTest);
+ defineReflectiveTests(PreferGenericFunctionTypeAliasesTest);
+ defineReflectiveTests(UseFunctionTypeSyntaxForParametersTest);
});
}
@reflectiveTest
-class ConvertToGenericFunctionSyntaxTest extends FixProcessorLintTest {
+class PreferGenericFunctionTypeAliasesTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.CONVERT_TO_GENERIC_FUNCTION_SYNTAX;
@@ -65,6 +66,15 @@
typedef F<P, R> = R Function(P x);
''');
}
+}
+
+@reflectiveTest
+class UseFunctionTypeSyntaxForParametersTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_GENERIC_FUNCTION_SYNTAX;
+
+ @override
+ String get lintCode => LintNames.use_function_type_syntax_for_parameters;
test_functionTypedParameter_noParameterTypes() async {
await resolveTestUnit('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart
index b50cf3a..dd47239 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart
@@ -59,6 +59,21 @@
''');
}
+ @failingTest
+ test_default_typeArg_linkedHashSet() async {
+ // LinkedHashSet isn't converted even though the lint reports that case.
+ await resolveTestUnit('''
+import 'dart:collection';
+
+var s = /*LINT*/LinkedHashSet<int>();
+''');
+ await assertHasFix('''
+import 'dart:collection';
+
+var s = /*LINT*/<int>{};
+''');
+ }
+
test_from_empty() async {
await resolveTestUnit('''
var s = /*LINT*/Set.from([]);
@@ -68,6 +83,20 @@
''');
}
+ @failingTest
+ test_from_inferred() async {
+ // _setWouldBeInferred does not check for inference based on the parameter
+ // type.
+ await resolveTestUnit('''
+void f(Set<int> s) {}
+var s = f(/*LINT*/Set.from([]));
+''');
+ await assertHasFix('''
+void f(Set<int> s) {}
+var s = f(/*LINT*/{});
+''');
+ }
+
test_from_newKeyword() async {
await resolveTestUnit('''
var s = /*LINT*/new Set.from([2, 3]);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_where_type_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_where_type_test.dart
new file mode 100644
index 0000000..035720c
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_where_type_test.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 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToWhereTypeTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToWhereTypeTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_WHERE_TYPE;
+
+ @override
+ String get lintCode => LintNames.prefer_iterable_whereType;
+
+ test_default_declaredType() async {
+ await resolveTestUnit('''
+Iterable<C> f(List<Object> list) {
+ return list./*LINT*/where((e) => e is C);
+}
+class C {}
+''');
+ await assertHasFix('''
+Iterable<C> f(List<Object> list) {
+ return list./*LINT*/whereType<C>();
+}
+class C {}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
index 819327f..6b98754 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -14,10 +15,61 @@
defineReflectiveTests(CreateMethodTest);
defineReflectiveTests(CreateMethodMixinTest);
defineReflectiveTests(CreateMethodWithExtensionMethodsTest);
+ defineReflectiveTests(AddMissingHashOrEqualsTest);
});
}
@reflectiveTest
+class AddMissingHashOrEqualsTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CREATE_METHOD;
+
+ @override
+ String get lintCode => LintNames.hash_and_equals;
+
+ test_equals() async {
+ await resolveTestUnit('''
+class C {
+ @override
+ int get /*LINT*/hashCode => 13;
+}
+''');
+ await assertHasFix('''
+class C {
+ @override
+ int get /*LINT*/hashCode => 13;
+
+ @override
+ bool operator ==(Object other) {
+ // TODO: implement ==
+ return super == other;
+ }
+}
+''');
+ }
+
+ test_hashCode() async {
+ await resolveTestUnit('''
+class C {
+ @override
+ bool operator /*LINT*/==(Object other) => false;
+}
+''');
+ await assertHasFix('''
+class C {
+ @override
+ bool operator /*LINT*/==(Object other) => false;
+
+ @override
+ // TODO: implement hashCode
+ int get hashCode => super.hashCode;
+
+}
+''');
+ }
+}
+
+@reflectiveTest
class CreateMethodMixinTest extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.CREATE_METHOD;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index b5e5f46..3721622 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -189,7 +189,7 @@
}
// Assert that none of the fixes are a fix-all fix.
- Fix foundFix = null;
+ Fix foundFix;
for (Fix fix in fixes) {
if (fix.isFixAllFix()) {
fail('A fix-all fix was found for the error: $error '
@@ -216,7 +216,7 @@
List<Fix> fixes = await _computeFixes(error);
// Assert that there exists such a fix in the list.
- Fix foundFix = null;
+ Fix foundFix;
for (Fix fix in fixes) {
if (fix.kind == kind && fix.isFixAllFix()) {
foundFix = fix;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
new file mode 100644
index 0000000..0fd0c22
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
@@ -0,0 +1,47 @@
+// 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/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(RemoveIfNullOperatorTest);
+ });
+}
+
+@reflectiveTest
+class RemoveIfNullOperatorTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.REMOVE_IF_NULL_OPERATOR;
+
+ @override
+ String get lintCode => LintNames.unnecessary_null_in_if_null_operators;
+
+ test_left() async {
+ await resolveTestUnit('''
+var a = '';
+var b = /*LINT*/null ?? a;
+''');
+ await assertHasFix('''
+var a = '';
+var b = /*LINT*/a;
+''');
+ }
+
+ test_right() async {
+ await resolveTestUnit('''
+var a = '';
+var b = /*LINT*/a ?? null;
+''');
+ await assertHasFix('''
+var a = '';
+var b = /*LINT*/a;
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 5f4a631..3a8d4a1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -57,6 +57,7 @@
import 'convert_to_single_quoted_string_test.dart'
as convert_to_single_quoted_string;
import 'convert_to_spread_test.dart' as convert_to_spread;
+import 'convert_to_where_type_test.dart' as convert_to_where_type;
import 'create_class_test.dart' as create_class;
import 'create_constructor_for_final_fields_test.dart'
as create_constructor_for_final_field;
@@ -97,6 +98,7 @@
as remove_empty_constructor_body;
import 'remove_empty_else_test.dart' as remove_empty_else;
import 'remove_empty_statement_test.dart' as remove_empty_statement;
+import 'remove_if_null_operator_test.dart' as remove_if_null_operator;
import 'remove_initializer_test.dart' as remove_initializer;
import 'remove_interpolation_braces_test.dart' as remove_interpolation_braces;
import 'remove_method_declaration_test.dart' as remove_method_declaration;
@@ -192,6 +194,7 @@
convert_to_set_literal.main();
convert_to_single_quoted_string.main();
convert_to_spread.main();
+ convert_to_where_type.main();
create_class.main();
create_constructor_for_final_field.main();
create_constructor_super.main();
@@ -230,6 +233,7 @@
remove_empty_constructor_body.main();
remove_empty_else.main();
remove_empty_statement.main();
+ remove_if_null_operator.main();
remove_initializer.main();
remove_interpolation_braces.main();
remove_method_declaration.main();
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
index a8be67d..4dfef6a 100644
--- a/pkg/analysis_server/test/stress/replay/replay.dart
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -370,7 +370,7 @@
// Iterate over the history, applying changes.
//
bool firstCheckout = true;
- ErrorMap expectedErrors = null;
+ ErrorMap expectedErrors;
Iterable<String> changedPubspecs;
while (iterator.moveNext()) {
//
@@ -506,7 +506,7 @@
/**
* Display usage information, preceded by the [errorMessage] if one is given.
*/
- void _showUsage(ArgParser parser, [String errorMessage = null]) {
+ void _showUsage(ArgParser parser, [String errorMessage]) {
if (errorMessage != null) {
stderr.writeln(errorMessage);
stderr.writeln();
@@ -607,7 +607,7 @@
addUpdateContent(AddContentOverlay(content));
for (List<SourceEdit> editList in editLists.reversed) {
for (SourceEdit edit in editList.reversed) {
- var overlay = null;
+ var overlay;
if (overlayStyle == OverlayStyle.change) {
overlay = ChangeContentOverlay([edit]);
} else if (overlayStyle == OverlayStyle.multipleAdd) {
diff --git a/pkg/analysis_server/test/stress/utilities/git.dart b/pkg/analysis_server/test/stress/utilities/git.dart
index 6d9532d..d0a827b 100644
--- a/pkg/analysis_server/test/stress/utilities/git.dart
+++ b/pkg/analysis_server/test/stress/utilities/git.dart
@@ -219,7 +219,7 @@
String srcPath = _makeAbsolute(input.substring(startIndex, endIndex));
startIndex = endIndex + 1;
// Parse field 14
- String dstPath = null;
+ String dstPath;
if (status.startsWith('C') || status.startsWith('R')) {
endIndex = _findEnd(input, startIndex);
dstPath = _makeAbsolute(input.substring(startIndex, endIndex));
@@ -406,7 +406,7 @@
*
* If a [commandSink] is provided, any calls to git will be written to it.
*/
- GitRepository(this.path, {this.logger = null});
+ GitRepository(this.path, {this.logger});
/**
* Checkout the given [commit] from the repository. This is done by running
diff --git a/pkg/analysis_server/test/stress/utilities/logger.dart b/pkg/analysis_server/test/stress/utilities/logger.dart
index bbdd406..56f68e5 100644
--- a/pkg/analysis_server/test/stress/utilities/logger.dart
+++ b/pkg/analysis_server/test/stress/utilities/logger.dart
@@ -33,7 +33,7 @@
* the [content] contains the actual information. If a list of [arguments] is
* provided, then they will be written after the content.
*/
- void log(String label, String content, {List<String> arguments = null}) {
+ void log(String label, String content, {List<String> arguments}) {
for (int i = _labelWidth - label.length; i > 0; i--) {
sink.write(' ');
}
diff --git a/pkg/analysis_server/test/stress/utilities/server.dart b/pkg/analysis_server/test/stress/utilities/server.dart
index ef98023..cf93f1d 100644
--- a/pkg/analysis_server/test/stress/utilities/server.dart
+++ b/pkg/analysis_server/test/stress/utilities/server.dart
@@ -80,7 +80,7 @@
* The time at which the response was received, or `null` if no response has
* been received.
*/
- int responseTime = null;
+ int responseTime;
/**
* The response that was received.
@@ -162,7 +162,7 @@
* The process in which the server is running, or `null` if the server hasn't
* been started yet.
*/
- Process _process = null;
+ Process _process;
/**
* Number that should be used to compute the 'id' to send in the next command
@@ -220,7 +220,7 @@
* If a [logger] is provided, the communications between the client (this
* test) and the server will be written to it.
*/
- Server({this.logger = null});
+ Server({this.logger});
/**
* Return a future that will complete when a 'server.status' notification is
diff --git a/pkg/analysis_server/test/timing/timing_framework.dart b/pkg/analysis_server/test/timing/timing_framework.dart
index c53e1f6..3e90901 100644
--- a/pkg/analysis_server/test/timing/timing_framework.dart
+++ b/pkg/analysis_server/test/timing/timing_framework.dart
@@ -108,7 +108,7 @@
*/
List<int> toMilliseconds(List<int> times) {
int count = times.length;
- List<int> convertedValues = List<int>();
+ List<int> convertedValues = <int>[];
for (int i = 0; i < count; i++) {
convertedValues.add(times[i] ~/ NANOSECONDS_PER_MILLISECOND);
}
@@ -224,7 +224,7 @@
* number of times.
*/
Future<TimingResult> run() async {
- List<int> times = List<int>();
+ List<int> times = <int>[];
await oneTimeSetUp();
await _repeat(warmupCount, null);
await _repeat(timingCount, times);
diff --git a/pkg/analysis_server/tool/instrumentation/log/log.dart b/pkg/analysis_server/tool/instrumentation/log/log.dart
index d627fbd..6048c5f 100644
--- a/pkg/analysis_server/tool/instrumentation/log/log.dart
+++ b/pkg/analysis_server/tool/instrumentation/log/log.dart
@@ -372,9 +372,9 @@
}
logEntries = <LogEntry>[];
analysisRanges = <EntryRange>[];
- NotificationEntry analysisStartEntry = null;
+ NotificationEntry analysisStartEntry;
int analysisStartIndex = -1;
- NotificationEntry pubStartEntry = null;
+ NotificationEntry pubStartEntry;
for (String line in logContent) {
LogEntry entry = LogEntry.from(logEntries.length, line);
if (entry != null) {
@@ -434,7 +434,7 @@
String id = entry.param('id');
if (id != null) {
_completionMap
- .putIfAbsent(id, () => List<NotificationEntry>())
+ .putIfAbsent(id, () => <NotificationEntry>[])
.add(entry);
}
}
@@ -626,7 +626,7 @@
* A list containing the descriptions of problems that were found while
* processing the log file, or `null` if no problems were found.
*/
- List<String> _problems = null;
+ List<String> _problems;
/**
* Initialize a newly created log entry with the given [timeStamp].
@@ -1104,12 +1104,12 @@
/**
* The name of the class implementing the task.
*/
- String _taskName = null;
+ String _taskName;
/**
* The description of the target of the task.
*/
- String _target = null;
+ String _target;
/**
* Initialize a newly created entry with the given [index] and [timeStamp] to
diff --git a/pkg/analysis_server/tool/instrumentation/page/log_page.dart b/pkg/analysis_server/tool/instrumentation/page/log_page.dart
index f872f7f..9150d38 100644
--- a/pkg/analysis_server/tool/instrumentation/page/log_page.dart
+++ b/pkg/analysis_server/tool/instrumentation/page/log_page.dart
@@ -37,7 +37,7 @@
* The number of entries to be written, or `null` if all of the entries should
* be written.
*/
- int pageLength = null;
+ int pageLength;
/**
* The number of digits in the event stamps that are the same for every entry.
@@ -133,7 +133,7 @@
* Write the given log [entry] to the given [sink].
*/
void _writeEntry(StringSink sink, LogEntry entry) {
- String id = null;
+ String id;
String clickHandler = 'clearHighlight()';
String icon = '';
String description = entry.kindName;
diff --git a/pkg/analysis_server/tool/instrumentation/page/stats_page.dart b/pkg/analysis_server/tool/instrumentation/page/stats_page.dart
index 36b9434..4025fd0 100644
--- a/pkg/analysis_server/tool/instrumentation/page/stats_page.dart
+++ b/pkg/analysis_server/tool/instrumentation/page/stats_page.dart
@@ -104,7 +104,7 @@
} else if (entry is RequestEntry) {
String method = entry.method;
int latency = entry.timeStamp - entry.clientRequestTime;
- latencyData.putIfAbsent(method, () => List<int>()).add(latency);
+ latencyData.putIfAbsent(method, () => <int>[]).add(latency);
if (method == 'completion.getSuggestions') {
ResponseEntry response = log.responseFor(entry);
if (response != null) {
@@ -128,9 +128,7 @@
int responseTime = response.timeStamp - entry.timeStamp;
var pluginData = pluginResponseData.putIfAbsent(
entry.pluginId, () => <String, List<int>>{});
- pluginData
- .putIfAbsent(entry.method, () => List<int>())
- .add(responseTime);
+ pluginData.putIfAbsent(entry.method, () => <int>[]).add(responseTime);
}
}
}
diff --git a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
index 82571278..4771a00 100644
--- a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
+++ b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
@@ -43,7 +43,7 @@
// Keep track of our base classes so they can look up their super classes
// later in their fromJson() to deserialise into the most specific type.
interface.baseTypes.forEach((base) {
- final subTypes = _subtypes[base.dartType] ??= List<String>();
+ final subTypes = _subtypes[base.dartType] ??= <String>[];
subTypes.add(interface.name);
});
});
diff --git a/pkg/analysis_server/tool/spec/codegen_java_types.dart b/pkg/analysis_server/tool/spec/codegen_java_types.dart
index a8a7063..9eedfa7 100644
--- a/pkg/analysis_server/tool/spec/codegen_java_types.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java_types.dart
@@ -56,7 +56,7 @@
GeneratedDirectory(pathToGenTypes, (String pkgPath) {
Api api = readApi(pkgPath);
Map<String, ImpliedType> impliedTypes = computeImpliedTypes(api);
- Map<String, FileContentsComputer> map = Map<String, FileContentsComputer>();
+ Map<String, FileContentsComputer> map = <String, FileContentsComputer>{};
for (ImpliedType impliedType in impliedTypes.values) {
String typeNameInSpec = capitalize(impliedType.camelName);
bool isRefactoringFeedback = impliedType.kind == 'refactoringFeedback';
@@ -73,7 +73,7 @@
typeNameInJava = _typeRenames[typeNameInSpec];
}
map['$typeNameInJava.java'] = (String pkgPath) async {
- String superclassName = null;
+ String superclassName;
if (isRefactoringFeedback) {
superclassName = 'RefactoringFeedback';
}
@@ -366,7 +366,7 @@
}));
write('public $className(');
// write out parameters to constructor
- List<String> parameters = List();
+ List<String> parameters = [];
if (className == 'Outline') {
parameters.add('Outline parent');
}
@@ -515,7 +515,7 @@
writeln(';');
}
write('return new $className(');
- List<String> parameters = List();
+ List<String> parameters = [];
for (TypeObjectField field in fields) {
if (!_isTypeFieldInUpdateContentUnionType(
className, field.name)) {
@@ -631,7 +631,7 @@
writeln('$className other = ($className) obj;');
writeln('return');
indent(() {
- List<String> equalsForField = List<String>();
+ List<String> equalsForField = <String>[];
for (TypeObjectField field in fields) {
equalsForField.add(_getEqualsLogicForField(field, 'other'));
}
diff --git a/pkg/analysis_server/tool/spec/from_html.dart b/pkg/analysis_server/tool/spec/from_html.dart
index 64c525d..c125d20 100644
--- a/pkg/analysis_server/tool/spec/from_html.dart
+++ b/pkg/analysis_server/tool/spec/from_html.dart
@@ -86,8 +86,8 @@
Api api;
List<String> versions = <String>[];
List<Domain> domains = <Domain>[];
- Types types = null;
- Refactorings refactorings = null;
+ Types types;
+ Refactorings refactorings;
recurse(html, 'api', {
'domain': (dom.Element element) {
domains.add(domainFromHtml(element));
@@ -120,7 +120,7 @@
void checkAttributes(
dom.Element element, List<String> requiredAttributes, String context,
{List<String> optionalAttributes = const []}) {
- Set<String> attributesFound = Set<String>();
+ Set<String> attributesFound = <String>{};
element.attributes.forEach((name, value) {
if (!requiredAttributes.contains(name) &&
!optionalAttributes.contains(name)) {
diff --git a/pkg/analysis_server/tool/spec/to_html.dart b/pkg/analysis_server/tool/spec/to_html.dart
index f684954..332556f 100644
--- a/pkg/analysis_server/tool/spec/to_html.dart
+++ b/pkg/analysis_server/tool/spec/to_html.dart
@@ -220,7 +220,7 @@
/**
* Set of types defined in the API.
*/
- Set<String> definedTypes = Set<String>();
+ Set<String> definedTypes = <String>{};
/**
* Mappings from HTML elements to API nodes.
@@ -418,7 +418,7 @@
* boldface.
*/
void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) {
- Set<String> fieldsToBold = Set<String>();
+ Set<String> fieldsToBold = <String>{};
if (typeForBolding != null) {
for (TypeObjectField field in typeForBolding.fields) {
fieldsToBold.add(field.name);
diff --git a/pkg/analysis_server_client/analysis_options.yaml b/pkg/analysis_server_client/analysis_options.yaml
index 3368902..38ce34f 100644
--- a/pkg/analysis_server_client/analysis_options.yaml
+++ b/pkg/analysis_server_client/analysis_options.yaml
@@ -33,7 +33,7 @@
- prefer_conditional_assignment
- prefer_contains
- prefer_equal_for_default_values
- #- prefer_final_fields # 2
+ - prefer_final_fields
- prefer_for_elements_to_map_fromIterable
- prefer_generic_function_type_aliases
- prefer_if_null_operators
diff --git a/pkg/analysis_server_client/lib/handler/connection_handler.dart b/pkg/analysis_server_client/lib/handler/connection_handler.dart
index 1360506..aada7f4 100644
--- a/pkg/analysis_server_client/lib/handler/connection_handler.dart
+++ b/pkg/analysis_server_client/lib/handler/connection_handler.dart
@@ -21,7 +21,7 @@
///
/// Clients may mix-in this class, but may not extend or implement it.
mixin ConnectionHandler implements NotificationHandler {
- Completer<bool> _connected = Completer();
+ final Completer<bool> _connected = Completer();
/// Clients should implement this method to return the server being managed.
/// This mixin will stop the server process if a connection cannot be
diff --git a/pkg/analysis_server_client/lib/server.dart b/pkg/analysis_server_client/lib/server.dart
index 6ee864f..f30db66 100644
--- a/pkg/analysis_server_client/lib/server.dart
+++ b/pkg/analysis_server_client/lib/server.dart
@@ -20,7 +20,7 @@
class Server {
/// If not `null`, [_listener] will be sent information
/// about interactions with the server.
- ServerListener _listener;
+ final ServerListener _listener;
/// Server process object, or `null` if server hasn't been started yet
/// or if the server has already been stopped.
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index fd8d3dd..b12d22e 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -16,6 +16,7 @@
bazelAnalysisOptionsPath,
flutterAnalysisOptionsPath;
import 'package:analyzer/src/context/context_root.dart';
+import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/context_root.dart' as api;
import 'package:analyzer/src/dart/analysis/driver.dart'
@@ -40,9 +41,7 @@
import 'package:analyzer/src/workspace/pub.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:args/args.dart';
-import 'package:package_config/packages.dart';
-import 'package:package_config/packages_file.dart';
-import 'package:package_config/src/packages_impl.dart';
+import 'package:package_config/packages.dart' as package_config;
import 'package:path/src/context.dart';
import 'package:yaml/yaml.dart';
@@ -182,16 +181,15 @@
return driver;
}
- Map<String, List<Folder>> convertPackagesToMap(Packages packages) {
- Map<String, List<Folder>> folderMap = HashMap<String, List<Folder>>();
- if (packages != null && packages != Packages.noPackages) {
- var pathContext = resourceProvider.pathContext;
- packages.asMap().forEach((String packageName, Uri uri) {
- String path = fileUriToNormalizedPath(pathContext, uri);
- folderMap[packageName] = [resourceProvider.getFolder(path)];
- });
+ /**
+ * Return an analysis options object containing the default option values.
+ */
+ AnalysisOptions createDefaultOptions() {
+ AnalysisOptions defaultOptions = builderOptions.defaultOptions;
+ if (defaultOptions == null) {
+ return AnalysisOptionsImpl();
}
- return folderMap;
+ return AnalysisOptionsImpl.from(defaultOptions);
}
// void _processAnalysisOptions(
@@ -217,25 +215,11 @@
// }
// }
- /**
- * Return an analysis options object containing the default option values.
- */
- AnalysisOptions createDefaultOptions() {
- AnalysisOptions defaultOptions = builderOptions.defaultOptions;
- if (defaultOptions == null) {
- return AnalysisOptionsImpl();
- }
- return AnalysisOptionsImpl.from(defaultOptions);
- }
-
Packages createPackageMap(String rootDirectoryPath) {
String filePath = builderOptions.defaultPackageFilePath;
if (filePath != null) {
File configFile = resourceProvider.getFile(filePath);
- List<int> bytes = configFile.readAsBytesSync();
- Map<String, Uri> map = parse(bytes, configFile.toUri());
- resolveSymbolicLinks(map);
- return MapPackages(map);
+ return parseDotPackagesFile(resourceProvider, configFile);
}
String directoryPath = builderOptions.defaultPackagesDirectoryPath;
if (directoryPath != null) {
@@ -276,27 +260,20 @@
* that is not found, it instead checks for the presence of a `packages/`
* directory in the same place. If that also fails, it starts checking parent
* directories for a `.packages` file, and stops if it finds it. Otherwise it
- * gives up and returns [Packages.noPackages].
+ * gives up and returns [Packages.empty].
*/
Packages findPackagesFromFile(String path) {
Resource location = _findPackagesLocation(path);
if (location is File) {
- List<int> fileBytes = location.readAsBytesSync();
- Map<String, Uri> map;
try {
- map =
- parse(fileBytes, resourceProvider.pathContext.toUri(location.path));
- } catch (exception) {
- // If we cannot read the file, then we respond as if the file did not
- // exist.
- return Packages.noPackages;
+ return parseDotPackagesFile(resourceProvider, location);
+ } catch (_) {
+ return Packages.empty;
}
- resolveSymbolicLinks(map);
- return MapPackages(map);
} else if (location is Folder) {
return getPackagesFromFolder(location);
}
- return Packages.noPackages;
+ return Packages.empty;
}
/**
@@ -380,11 +357,7 @@
}
} else {
// Search for the default analysis options.
- // TODO(danrubel) determine if bazel or gn project depends upon flutter
- Source source;
- if (workspace.hasFlutterDependency) {
- source = sourceFactory.forUri(flutterAnalysisOptionsPath);
- }
+ Source source = sourceFactory.forUri(flutterAnalysisOptionsPath);
if (source == null || !source.exists()) {
source = sourceFactory.forUri(bazelAnalysisOptionsPath);
}
@@ -461,20 +434,29 @@
*
* Package names are resolved as relative to sub-directories of the package
* directory.
+ *
+ * TODO(scheglov) Remove this feature
*/
Packages getPackagesFromFolder(Folder folder) {
Context pathContext = resourceProvider.pathContext;
- Map<String, Uri> map = HashMap<String, Uri>();
+ var map = <String, Package>{};
for (Resource child in folder.getChildren()) {
if (child is Folder) {
// Inline resolveSymbolicLinks for performance reasons.
String packageName = pathContext.basename(child.path);
- String folderPath = resolveSymbolicLink(child);
- String uriPath = pathContext.join(folderPath, '.');
- map[packageName] = pathContext.toUri(uriPath);
+ String packagePath = resolveSymbolicLink(child);
+ var rootFolder = resourceProvider.getFolder(packagePath);
+ var libFolder = rootFolder.getChildAssumingFolder('lib');
+ var package = Package(
+ name: packageName,
+ rootFolder: rootFolder,
+ libFolder: libFolder,
+ languageVersion: null,
+ );
+ map[packageName] = package;
}
}
- return MapPackages(map);
+ return Packages(map);
}
/**
@@ -520,37 +502,20 @@
* if neither is found.
*/
Resource _findPackagesLocation(String path) {
- Folder folder = resourceProvider.getFolder(path);
- if (!folder.exists) {
- return null;
- }
+ var resource = resourceProvider.getResource(path);
+ while (resource != null) {
+ if (resource is Folder) {
+ var dotPackagesFile = resource.getChildAssumingFile('.packages');
+ if (dotPackagesFile.exists) {
+ return dotPackagesFile;
+ }
- File checkForConfigFile(Folder folder) {
- File file = folder.getChildAssumingFile('.packages');
- if (file.exists) {
- return file;
+ var packagesDirectory = resource.getChildAssumingFolder('packages');
+ if (packagesDirectory.exists) {
+ return packagesDirectory;
+ }
}
- return null;
- }
-
- // Check for $cwd/.packages
- File packagesCfgFile = checkForConfigFile(folder);
- if (packagesCfgFile != null) {
- return packagesCfgFile;
- }
- // Check for $cwd/packages/
- Folder packagesDir = folder.getChildAssumingFolder("packages");
- if (packagesDir.exists) {
- return packagesDir;
- }
- // Check for cwd(/..)+/.packages
- Folder parentDir = folder.parent;
- while (parentDir != null) {
- packagesCfgFile = checkForConfigFile(parentDir);
- if (packagesCfgFile != null) {
- return packagesCfgFile;
- }
- parentDir = parentDir.parent;
+ resource = resource.parent;
}
return null;
}
@@ -573,24 +538,45 @@
return null;
}
+ static Map<String, List<Folder>> convertPackagesToMap(
+ ResourceProvider resourceProvider,
+ package_config.Packages packages,
+ ) {
+ Map<String, List<Folder>> folderMap = HashMap<String, List<Folder>>();
+ if (packages != null && packages != package_config.Packages.noPackages) {
+ var pathContext = resourceProvider.pathContext;
+ packages.asMap().forEach((String packageName, Uri uri) {
+ String path = fileUriToNormalizedPath(pathContext, uri);
+ folderMap[packageName] = [resourceProvider.getFolder(path)];
+ });
+ }
+ return folderMap;
+ }
+
static Workspace createWorkspace(ResourceProvider resourceProvider,
String rootPath, ContextBuilder contextBuilder) {
+ var packages = contextBuilder.createPackageMap(rootPath);
+ var packageMap = <String, List<Folder>>{};
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
+
if (_hasPackageFileInPath(resourceProvider, rootPath)) {
// A Bazel or Gn workspace that includes a '.packages' file is treated
// like a normal (non-Bazel/Gn) directory. But may still use
// package:build or Pub.
return PackageBuildWorkspace.find(
- resourceProvider, rootPath, contextBuilder) ??
- PubWorkspace.find(resourceProvider, rootPath, contextBuilder) ??
- BasicWorkspace.find(resourceProvider, rootPath, contextBuilder);
+ resourceProvider, packageMap, rootPath) ??
+ PubWorkspace.find(resourceProvider, packageMap, rootPath) ??
+ BasicWorkspace.find(resourceProvider, packageMap, rootPath);
}
Workspace workspace = BazelWorkspace.find(resourceProvider, rootPath);
workspace ??= GnWorkspace.find(resourceProvider, rootPath);
workspace ??=
- PackageBuildWorkspace.find(resourceProvider, rootPath, contextBuilder);
- workspace ??= PubWorkspace.find(resourceProvider, rootPath, contextBuilder);
- return workspace ??
- BasicWorkspace.find(resourceProvider, rootPath, contextBuilder);
+ PackageBuildWorkspace.find(resourceProvider, packageMap, rootPath);
+ workspace ??= PubWorkspace.find(resourceProvider, packageMap, rootPath);
+ workspace ??= BasicWorkspace.find(resourceProvider, packageMap, rootPath);
+ return workspace;
}
/**
diff --git a/pkg/analyzer/lib/src/context/packages.dart b/pkg/analyzer/lib/src/context/packages.dart
index 51c57ce..2552f33 100644
--- a/pkg/analyzer/lib/src/context/packages.dart
+++ b/pkg/analyzer/lib/src/context/packages.dart
@@ -96,6 +96,8 @@
}
class Packages {
+ static final empty = Packages({});
+
final Map<String, Package> _map;
Packages(Map<String, Package> map) : _map = map;
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 808919f..a257211 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -4646,8 +4646,6 @@
_body = _becomeParentOf(body);
}
- ForStatementImpl._();
-
@override
Statement get body => _body;
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
new file mode 100644
index 0000000..061b865
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -0,0 +1,338 @@
+// 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/ast/token.dart';
+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/error/listener.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/resolution_result.dart';
+import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/type_promotion_manager.dart';
+import 'package:analyzer/src/generated/type_system.dart';
+import 'package:analyzer/src/task/strong/checker.dart';
+import 'package:meta/meta.dart';
+
+/// Helper for resolving [BinaryExpression]s.
+class BinaryExpressionResolver {
+ final ResolverVisitor _resolver;
+ final TypePromotionManager _promoteManager;
+ final FlowAnalysisHelper _flowAnalysis;
+ final ElementTypeProvider _elementTypeProvider;
+ final TypePropertyResolver _typePropertyResolver;
+ final InvocationInferenceHelper _inferenceHelper;
+
+ BinaryExpressionResolver({
+ @required ResolverVisitor resolver,
+ @required TypePromotionManager promoteManager,
+ @required FlowAnalysisHelper flowAnalysis,
+ @required ElementTypeProvider elementTypeProvider,
+ }) : _resolver = resolver,
+ _promoteManager = promoteManager,
+ _flowAnalysis = flowAnalysis,
+ _elementTypeProvider = elementTypeProvider,
+ _typePropertyResolver = resolver.typePropertyResolver,
+ _inferenceHelper = resolver.inferenceHelper;
+
+ ErrorReporter get _errorReporter => _resolver.errorReporter;
+
+ bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
+
+ TypeProvider get _typeProvider => _resolver.typeProvider;
+
+ TypeSystemImpl get _typeSystem => _resolver.typeSystem;
+
+ void resolve(BinaryExpressionImpl node) {
+ TokenType operator = node.operator.type;
+ Expression left = node.leftOperand;
+ Expression right = node.rightOperand;
+ var flow = _flowAnalysis?.flow;
+
+ if (operator == TokenType.AMPERSAND_AMPERSAND) {
+ InferenceContext.setType(left, _typeProvider.boolType);
+ InferenceContext.setType(right, _typeProvider.boolType);
+
+ // TODO(scheglov) Do we need these checks for null?
+ left?.accept(_resolver);
+
+ if (_flowAnalysis != null) {
+ flow?.logicalBinaryOp_rightBegin(left, isAnd: true);
+ _flowAnalysis.checkUnreachableNode(right);
+ right.accept(_resolver);
+ flow?.logicalBinaryOp_end(node, right, isAnd: true);
+ } else {
+ _promoteManager.visitBinaryExpression_and_rhs(
+ left,
+ right,
+ () {
+ right.accept(_resolver);
+ },
+ );
+ }
+
+ _resolve1(node);
+ } else if (operator == TokenType.BAR_BAR) {
+ InferenceContext.setType(left, _typeProvider.boolType);
+ InferenceContext.setType(right, _typeProvider.boolType);
+
+ // TODO(scheglov) Do we need these checks for null?
+ left?.accept(_resolver);
+
+ flow?.logicalBinaryOp_rightBegin(left, isAnd: false);
+ _flowAnalysis?.checkUnreachableNode(right);
+ right.accept(_resolver);
+ flow?.logicalBinaryOp_end(node, right, isAnd: false);
+
+ _resolve1(node);
+ } else if (operator == TokenType.BANG_EQ || operator == TokenType.EQ_EQ) {
+ left.accept(_resolver);
+ _flowAnalysis?.flow?.equalityOp_rightBegin(left);
+ right.accept(_resolver);
+ _resolve1(node);
+ _flowAnalysis?.flow?.equalityOp_end(node, right,
+ notEqual: operator == TokenType.BANG_EQ);
+ } else {
+ if (operator == TokenType.QUESTION_QUESTION) {
+ var leftContextType = InferenceContext.getContext(node);
+ if (leftContextType != null && _isNonNullableByDefault) {
+ leftContextType = _typeSystem.makeNullable(leftContextType);
+ }
+ InferenceContext.setType(left, leftContextType);
+ }
+ // TODO(scheglov) Do we need these checks for null?
+ left?.accept(_resolver);
+
+ // Call ElementResolver.visitBinaryExpression to resolve the user-defined
+ // operator method, if applicable.
+ _resolve1(node);
+
+ if (operator == TokenType.QUESTION_QUESTION) {
+ // Set the right side, either from the context, or using the information
+ // from the left side if it is more precise.
+ DartType contextType = InferenceContext.getContext(node);
+ DartType leftType = left?.staticType;
+ if (contextType == null || contextType.isDynamic) {
+ contextType = leftType;
+ }
+ InferenceContext.setType(right, contextType);
+ } else {
+ var invokeType = node.staticInvokeType;
+ if (invokeType != null && invokeType.parameters.isNotEmpty) {
+ // If this is a user-defined operator, set the right operand context
+ // using the operator method's parameter type.
+ var rightParam = invokeType.parameters[0];
+ InferenceContext.setType(
+ right, _elementTypeProvider.getVariableType(rightParam));
+ }
+ }
+
+ if (operator == TokenType.QUESTION_QUESTION) {
+ flow?.ifNullExpression_rightBegin(node.leftOperand);
+ right.accept(_resolver);
+ flow?.ifNullExpression_end();
+ } else {
+ // TODO(scheglov) Do we need these checks for null?
+ right?.accept(_resolver);
+ }
+ }
+ _resolve2(node);
+ }
+
+ /// Set the static type of [node] to be the least upper bound of the static
+ /// types of subexpressions [expr1] and [expr2].
+ ///
+ /// TODO(scheglov) this is duplicate
+ void _analyzeLeastUpperBound(
+ Expression node, Expression expr1, Expression expr2,
+ {bool read = false}) {
+ DartType staticType1 = _getExpressionType(expr1, read: read);
+ DartType staticType2 = _getExpressionType(expr2, read: read);
+
+ _analyzeLeastUpperBoundTypes(node, staticType1, staticType2);
+ }
+
+ /// Set the static type of [node] to be the least upper bound of the static
+ /// types [staticType1] and [staticType2].
+ ///
+ /// TODO(scheglov) this is duplicate
+ void _analyzeLeastUpperBoundTypes(
+ Expression node, DartType staticType1, DartType staticType2) {
+ if (staticType1 == null) {
+ // TODO(brianwilkerson) Determine whether this can still happen.
+ staticType1 = DynamicTypeImpl.instance;
+ }
+
+ if (staticType2 == null) {
+ // TODO(brianwilkerson) Determine whether this can still happen.
+ staticType2 = DynamicTypeImpl.instance;
+ }
+
+ DartType staticType =
+ _typeSystem.getLeastUpperBound(staticType1, staticType2) ??
+ DynamicTypeImpl.instance;
+
+ staticType = _resolver.toLegacyTypeIfOptOut(staticType);
+
+ _inferenceHelper.recordStaticType(node, staticType);
+ }
+
+ /// Gets the definite type of expression, which can be used in cases where
+ /// the most precise type is desired, for example computing the least upper
+ /// bound.
+ ///
+ /// See [getExpressionType] for more information. Without strong mode, this is
+ /// equivalent to [_getStaticType].
+ ///
+ /// TODO(scheglov) this is duplicate
+ DartType _getExpressionType(Expression expr, {bool read = false}) =>
+ getExpressionType(expr, _typeSystem, _typeProvider,
+ read: read, elementTypeProvider: _elementTypeProvider);
+
+ /// Return the static type of the given [expression] that is to be used for
+ /// type analysis.
+ ///
+ /// TODO(scheglov) this is duplicate
+ DartType _getStaticType(Expression expression, {bool read = false}) {
+ if (expression is NullLiteral) {
+ return _typeProvider.nullType;
+ }
+ DartType type = read
+ ? getReadType(expression, elementTypeProvider: _elementTypeProvider)
+ : expression.staticType;
+ return _resolveTypeParameter(type);
+ }
+
+ void _resolve1(BinaryExpressionImpl node) {
+ Token operator = node.operator;
+ if (operator.isUserDefinableOperator) {
+ _resolveBinaryExpression(node, operator.lexeme);
+ } else if (operator.type == TokenType.BANG_EQ) {
+ _resolveBinaryExpression(node, TokenType.EQ_EQ.lexeme);
+ }
+ }
+
+ void _resolve2(BinaryExpressionImpl node) {
+ if (node.operator.type == TokenType.QUESTION_QUESTION) {
+ if (_isNonNullableByDefault) {
+ // The static type of a compound assignment using ??= with NNBD is the
+ // least upper bound of the static types of the LHS and RHS after
+ // promoting the LHS/ to non-null (as we know its value will not be used
+ // if null)
+ _analyzeLeastUpperBoundTypes(
+ node,
+ _typeSystem.promoteToNonNull(
+ _getExpressionType(node.leftOperand, read: true)),
+ _getExpressionType(node.rightOperand, read: true));
+ } else {
+ // Without NNBD, evaluation of an if-null expression e of the form
+ // e1 ?? e2 is equivalent to the evaluation of the expression
+ // ((x) => x == null ? e2 : x)(e1). The static type of e is the least
+ // upper bound of the static type of e1 and the static type of e2.
+ _analyzeLeastUpperBound(node, node.leftOperand, node.rightOperand);
+ }
+ return;
+ }
+
+ if (identical(node.leftOperand.staticType, NeverTypeImpl.instance)) {
+ _inferenceHelper.recordStaticType(node, NeverTypeImpl.instance);
+ return;
+ }
+
+ DartType staticType =
+ node.staticInvokeType?.returnType ?? DynamicTypeImpl.instance;
+ if (node.leftOperand is! ExtensionOverride) {
+ staticType = _typeSystem.refineBinaryExpressionType(
+ _getStaticType(node.leftOperand),
+ node.operator.type,
+ node.rightOperand.staticType,
+ staticType,
+ );
+ }
+ _inferenceHelper.recordStaticType(node, staticType);
+ }
+
+ void _resolveBinaryExpression(BinaryExpression node, String methodName) {
+ Expression leftOperand = node.leftOperand;
+
+ if (leftOperand is ExtensionOverride) {
+ ExtensionElement extension = leftOperand.extensionName.staticElement;
+ MethodElement member = extension.getMethod(methodName);
+ if (member == null) {
+ _errorReporter.reportErrorForToken(
+ CompileTimeErrorCode.UNDEFINED_EXTENSION_OPERATOR,
+ node.operator,
+ [methodName, extension.name],
+ );
+ }
+ node.staticElement = member;
+ return;
+ }
+
+ var leftType = _getStaticType(leftOperand);
+
+ if (identical(leftType, NeverTypeImpl.instance)) {
+ _resolver.errorReporter.reportErrorForNode(
+ StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ leftOperand,
+ );
+ return;
+ }
+
+ ResolutionResult result = _typePropertyResolver.resolve(
+ receiver: leftOperand,
+ receiverType: leftType,
+ name: methodName,
+ receiverErrorNode: leftOperand,
+ nameErrorNode: node,
+ );
+
+ node.staticElement = result.getter;
+ node.staticInvokeType =
+ _elementTypeProvider.safeExecutableType(result.getter);
+ if (_shouldReportInvalidMember(leftType, result)) {
+ if (leftOperand is SuperExpression) {
+ _errorReporter.reportErrorForToken(
+ StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
+ node.operator,
+ [methodName, leftType],
+ );
+ } else {
+ _errorReporter.reportErrorForToken(
+ StaticTypeWarningCode.UNDEFINED_OPERATOR,
+ node.operator,
+ [methodName, leftType],
+ );
+ }
+ }
+ }
+
+ /// If the given [type] is a type parameter, resolve it to the type that should
+ /// be used when looking up members. Otherwise, return the original type.
+ ///
+ /// TODO(scheglov) this is duplicate
+ DartType _resolveTypeParameter(DartType type) =>
+ type?.resolveToBound(_typeProvider.objectType);
+
+ /// Return `true` if we should report an error for the lookup [result] on
+ /// the [type].
+ ///
+ /// TODO(scheglov) this is duplicate
+ bool _shouldReportInvalidMember(DartType type, ResolutionResult result) {
+ if (result.isNone && type != null && !type.isDynamic) {
+ if (_isNonNullableByDefault && _typeSystem.isPotentiallyNullable(type)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index 1b410fc..6acef20 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -14,7 +14,6 @@
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/element_type_provider.dart';
import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/type_system.dart';
import 'package:meta/meta.dart';
/// Helper for resolving [FunctionExpressionInvocation]s.
@@ -36,8 +35,6 @@
ExtensionMemberResolver get _extensionResolver => _resolver.extensionResolver;
- TypeSystemImpl get _typeSystem => _resolver.typeSystem;
-
void resolve(FunctionExpressionInvocationImpl node) {
var rawType = _resolveCallElement(node);
@@ -49,22 +46,10 @@
return;
}
- var invokeType = _instantiateInvokeType(node, rawType);
-
- node.staticInvokeType = invokeType;
-
- var argumentList = node.argumentList;
- var parameters = ResolverVisitor.resolveArgumentsToParameters(
- argumentList,
- invokeType.parameters,
- _errorReporter.reportErrorForNode,
+ _inferenceHelper.resolveFunctionExpressionInvocation(
+ node: node,
+ rawType: rawType,
);
- argumentList.correspondingStaticParameters = parameters;
-
- _inferenceHelper.inferArgumentTypesForInvocation(node, rawType);
- _resolveArguments(node);
-
- _inferenceHelper.inferGenericInvocationExpression(node, rawType);
var returnType = _inferenceHelper.computeInvokeReturnType(
node.staticInvokeType,
@@ -73,35 +58,6 @@
_inferenceHelper.recordStaticType(node, returnType);
}
- FunctionType _instantiateInvokeType(
- FunctionExpressionInvocation node,
- FunctionType rawType,
- ) {
- var typeParameters = rawType.typeFormals;
-
- var arguments = node.typeArguments?.arguments;
- if (arguments != null && arguments.length != typeParameters.length) {
- // TODO(scheglov) The error is suboptimal for this node type.
- _errorReporter.reportErrorForNode(
- StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
- node,
- [rawType, typeParameters.length, arguments.length],
- );
- // Wrong number of type arguments. Ignore them.
- arguments = null;
- }
-
- if (typeParameters.isEmpty) {
- return rawType;
- }
-
- if (arguments == null) {
- return _typeSystem.instantiateToBounds(rawType);
- } else {
- return rawType.instantiate(arguments.map((n) => n.type).toList());
- }
- }
-
void _resolveArguments(FunctionExpressionInvocationImpl node) {
node.argumentList.accept(_resolver);
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index db2da5f..4275f25 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -12,26 +12,31 @@
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/element_type_provider.dart';
import 'package:analyzer/src/generated/migration.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:meta/meta.dart';
class InvocationInferenceHelper {
- final LibraryElementImpl _definingLibrary;
+ final ResolverVisitor _resolver;
final ElementTypeProvider _elementTypeProvider;
final ErrorReporter _errorReporter;
final FlowAnalysisHelper _flowAnalysis;
final TypeSystemImpl _typeSystem;
final TypeProviderImpl _typeProvider;
+ List<DartType> _typeArgumentTypes;
+ FunctionType _invokeType;
+
InvocationInferenceHelper({
+ @required ResolverVisitor resolver,
@required LibraryElementImpl definingLibrary,
@required ElementTypeProvider elementTypeProvider,
@required ErrorReporter errorReporter,
@required FlowAnalysisHelper flowAnalysis,
@required TypeSystemImpl typeSystem,
- }) : _definingLibrary = definingLibrary,
+ }) : _resolver = resolver,
_elementTypeProvider = elementTypeProvider,
_errorReporter = errorReporter,
_typeSystem = typeSystem,
@@ -40,16 +45,10 @@
/// Compute the return type of the method or function represented by the given
/// type that is being invoked.
- DartType /*!*/ computeInvokeReturnType(DartType type,
+ DartType computeInvokeReturnType(DartType type,
{@required bool isNullAware}) {
- TypeImpl /*!*/ returnType;
- if (type is InterfaceType) {
- MethodElement callMethod = type.lookUpMethod2(
- FunctionElement.CALL_METHOD_NAME, _definingLibrary);
- returnType =
- _elementTypeProvider.safeExecutableType(callMethod)?.returnType ??
- DynamicTypeImpl.instance;
- } else if (type is FunctionType) {
+ TypeImpl returnType;
+ if (type is FunctionType) {
returnType = type.returnType ?? DynamicTypeImpl.instance;
} else {
returnType = DynamicTypeImpl.instance;
@@ -137,27 +136,11 @@
fnType is FunctionType &&
fnType.typeFormals.isNotEmpty) {
// Get the parameters that correspond to the uninstantiated generic.
- List<ParameterElement> rawParameters =
- ResolverVisitor.resolveArgumentsToParameters(
- argumentList, fnType.parameters, null);
-
- List<ParameterElement> params = <ParameterElement>[];
- List<DartType> argTypes = <DartType>[];
- for (int i = 0, length = rawParameters.length; i < length; i++) {
- ParameterElement parameter = rawParameters[i];
- if (parameter != null) {
- params.add(parameter);
- argTypes.add(argumentList.arguments[i].staticType);
- }
- }
- var typeArgs = _typeSystem.inferGenericFunctionOrType(
- typeParameters: fnType.typeFormals,
- parameters: params,
- declaredReturnType: fnType.returnType,
- argumentTypes: argTypes,
- contextReturnType: InferenceContext.getContext(node),
+ List<DartType> typeArgs = _inferUpwards(
+ rawType: fnType,
+ argumentList: argumentList,
+ contextType: InferenceContext.getContext(node),
isConst: isConst,
- errorReporter: _errorReporter,
errorNode: errorNode,
);
if (node is InvocationExpressionImpl) {
@@ -249,6 +232,230 @@
}
}
+ /// Finish resolution of the [FunctionExpressionInvocation].
+ ///
+ /// We have already found the invoked [ExecutableElement], and the [rawType]
+ /// is its not yet instantiated type. Here we perform downwards inference,
+ /// resolution of arguments, and upwards inference.
+ void resolveFunctionExpressionInvocation({
+ @required FunctionExpressionInvocationImpl node,
+ @required FunctionType rawType,
+ }) {
+ _resolveInvocation(
+ rawType: rawType,
+ typeArgumentList: node.typeArguments,
+ argumentList: node.argumentList,
+ contextType: InferenceContext.getContext(node),
+ isConst: false,
+ errorNode: node.function,
+ );
+
+ node.typeArgumentTypes = _typeArgumentTypes;
+ node.staticInvokeType = _invokeType;
+ }
+
+ /// Finish resolution of the [MethodInvocation].
+ ///
+ /// We have already found the invoked [ExecutableElement], and the [rawType]
+ /// is its not yet instantiated type. Here we perform downwards inference,
+ /// resolution of arguments, and upwards inference.
+ void resolveMethodInvocation({
+ @required MethodInvocationImpl node,
+ @required FunctionType rawType,
+ }) {
+ _resolveInvocation(
+ rawType: rawType,
+ typeArgumentList: node.typeArguments,
+ argumentList: node.argumentList,
+ contextType: InferenceContext.getContext(node),
+ isConst: false,
+ errorNode: node.function,
+ );
+
+ node.typeArgumentTypes = _typeArgumentTypes;
+ node.staticInvokeType = _invokeType;
+
+ var returnType = computeInvokeReturnType(
+ _invokeType,
+ isNullAware: node.isNullAware,
+ );
+ recordStaticType(node, returnType);
+ }
+
+ List<DartType> _inferDownwards({
+ @required FunctionType rawType,
+ @required DartType contextType,
+ @required bool isConst,
+ @required AstNode errorNode,
+ }) {
+ return _typeSystem.inferGenericFunctionOrType(
+ typeParameters: rawType.typeFormals,
+ parameters: const <ParameterElement>[],
+ declaredReturnType: rawType.returnType,
+ argumentTypes: const <DartType>[],
+ contextReturnType: contextType,
+ downwards: true,
+ isConst: isConst,
+ errorReporter: _errorReporter,
+ errorNode: errorNode,
+ );
+ }
+
+ /// TODO(scheglov) Instead of [isConst] sanitize [contextType] before calling.
+ List<DartType> _inferUpwards({
+ @required FunctionType rawType,
+ @required DartType contextType,
+ @required ArgumentList argumentList,
+ @required bool isConst,
+ @required AstNode errorNode,
+ }) {
+ // Get the parameters that correspond to the uninstantiated generic.
+ List<ParameterElement> rawParameters =
+ ResolverVisitor.resolveArgumentsToParameters(
+ argumentList, rawType.parameters, null);
+
+ List<ParameterElement> params = <ParameterElement>[];
+ List<DartType> argTypes = <DartType>[];
+ for (int i = 0, length = rawParameters.length; i < length; i++) {
+ ParameterElement parameter = rawParameters[i];
+ if (parameter != null) {
+ params.add(parameter);
+ argTypes.add(argumentList.arguments[i].staticType);
+ }
+ }
+ var typeArgs = _typeSystem.inferGenericFunctionOrType(
+ typeParameters: rawType.typeFormals,
+ parameters: params,
+ declaredReturnType: rawType.returnType,
+ argumentTypes: argTypes,
+ contextReturnType: contextType,
+ isConst: isConst,
+ errorReporter: _errorReporter,
+ errorNode: errorNode,
+ );
+ return typeArgs;
+ }
+
+ void _resolveArguments(ArgumentList argumentList) {
+ argumentList.accept(_resolver);
+ }
+
+ void _resolveInvocation({
+ @required FunctionType rawType,
+ @required DartType contextType,
+ @required TypeArgumentList typeArgumentList,
+ @required ArgumentList argumentList,
+ @required bool isConst,
+ @required AstNode errorNode,
+ }) {
+ if (typeArgumentList != null) {
+ _resolveInvocationWithTypeArguments(
+ rawType: rawType,
+ typeArgumentList: typeArgumentList,
+ argumentList: argumentList,
+ );
+ } else {
+ _resolveInvocationWithoutTypeArguments(
+ rawType: rawType,
+ contextType: contextType,
+ argumentList: argumentList,
+ isConst: isConst,
+ errorNode: errorNode,
+ );
+ }
+ _setCorrespondingParameters(argumentList, _invokeType);
+ }
+
+ void _resolveInvocationWithoutTypeArguments({
+ @required FunctionType rawType,
+ @required DartType contextType,
+ @required ArgumentList argumentList,
+ @required bool isConst,
+ @required AstNode errorNode,
+ }) {
+ var typeParameters = rawType.typeFormals;
+
+ if (typeParameters.isEmpty) {
+ InferenceContext.setType(argumentList, rawType);
+ _resolveArguments(argumentList);
+
+ _typeArgumentTypes = const <DartType>[];
+ _invokeType = rawType;
+ } else {
+ rawType = _getFreshType(rawType);
+
+ List<DartType> downwardsTypeArguments = _inferDownwards(
+ rawType: rawType,
+ contextType: contextType,
+ isConst: isConst,
+ errorNode: errorNode,
+ );
+
+ var downwardsInvokeType = rawType.instantiate(downwardsTypeArguments);
+ InferenceContext.setType(argumentList, downwardsInvokeType);
+
+ _resolveArguments(argumentList);
+
+ _typeArgumentTypes = _inferUpwards(
+ rawType: rawType,
+ argumentList: argumentList,
+ contextType: contextType,
+ isConst: isConst,
+ errorNode: errorNode,
+ );
+ _invokeType = rawType.instantiate(_typeArgumentTypes);
+ }
+ }
+
+ void _resolveInvocationWithTypeArguments({
+ FunctionType rawType,
+ TypeArgumentList typeArgumentList,
+ ArgumentList argumentList,
+ }) {
+ var typeParameters = rawType.typeFormals;
+
+ List<DartType> typeArguments;
+ if (typeArgumentList.arguments.length != typeParameters.length) {
+ _errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
+ typeArgumentList,
+ [
+ rawType,
+ typeParameters.length,
+ typeArgumentList.arguments.length,
+ ],
+ );
+ typeArguments = List.filled(
+ typeParameters.length,
+ DynamicTypeImpl.instance,
+ );
+ } else {
+ typeArguments = typeArgumentList.arguments
+ .map((typeArgument) => typeArgument.type)
+ .toList(growable: true);
+ }
+
+ var invokeType = rawType.instantiate(typeArguments);
+ InferenceContext.setType(argumentList, invokeType);
+
+ _resolveArguments(argumentList);
+
+ _typeArgumentTypes = typeArguments;
+ _invokeType = invokeType;
+ }
+
+ void _setCorrespondingParameters(
+ ArgumentList argumentList,
+ FunctionType invokeType,
+ ) {
+ var parameters = ResolverVisitor.resolveArgumentsToParameters(
+ argumentList,
+ invokeType.parameters,
+ _errorReporter.reportErrorForNode,
+ );
+ argumentList.correspondingStaticParameters = parameters;
+ }
+
static DartType _getFreshType(DartType type) {
if (type is FunctionType) {
var parameters = getFreshTypeParameters(type.typeFormals);
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index a5ec37b..a80d2d0 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -12,7 +12,6 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
-import 'package:analyzer/src/dart/resolver/resolution_result.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/element_type_provider.dart';
@@ -175,45 +174,40 @@
}
}
- /// Check for a generic type, and apply type arguments.
- FunctionType _instantiateFunctionType(
- FunctionType invokeType, TypeArgumentList typeArguments, AstNode node) {
- var typeFormals = invokeType.typeFormals;
- var arguments = typeArguments?.arguments;
- if (arguments != null && arguments.length != typeFormals.length) {
- _resolver.errorReporter.reportErrorForNode(
- StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
- node,
- [invokeType, typeFormals.length, arguments?.length ?? 0]);
- arguments = null;
- }
-
- if (typeFormals.isNotEmpty) {
- if (arguments == null) {
- var typeArguments =
- _typeSystem.instantiateTypeFormalsToBounds(typeFormals);
- _invocation.typeArgumentTypes = typeArguments;
- return invokeType.instantiate(typeArguments);
- } else {
- var typeArguments = arguments.map((n) => n.type).toList();
- _invocation.typeArgumentTypes = typeArguments;
- return invokeType.instantiate(typeArguments);
- }
- } else {
- _invocation.typeArgumentTypes = const <DartType>[];
- }
-
- return invokeType;
- }
-
bool _isCoreFunction(DartType type) {
// TODO(scheglov) Can we optimize this?
return type is InterfaceType && type.isDartCoreFunction;
}
- ExecutableElement _lookUpClassMember(ClassElement element, String name) {
- // TODO(scheglov) Use class hierarchy.
- return element.lookUpMethod(name, _definingLibrary);
+ void _reportInstanceAccessToStaticMember(
+ SimpleIdentifier nameNode,
+ ExecutableElement element,
+ bool nullReceiver,
+ ) {
+ if (_resolver.enclosingExtension != null) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
+ nameNode,
+ [element.enclosingElement.displayName],
+ );
+ } else if (nullReceiver) {
+ _resolver.errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
+ nameNode,
+ [element.enclosingElement.displayName],
+ );
+ } else {
+ _resolver.errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
+ nameNode,
+ [
+ nameNode.name,
+ element.kind.displayName,
+ element.enclosingElement.displayName,
+ ],
+ );
+ }
}
void _reportInvocationOfNonFunction(MethodInvocation node) {
@@ -310,17 +304,6 @@
}
}
- /// Given an [argumentList] and the [parameters] related to the element that
- /// will be invoked using those arguments, compute the list of parameters that
- /// correspond to the list of arguments. An error will be reported if any of
- /// the arguments cannot be matched to a parameter. Return the parameters that
- /// correspond to the arguments.
- List<ParameterElement> _resolveArgumentsToParameters(
- ArgumentList argumentList, List<ParameterElement> parameters) {
- return ResolverVisitor.resolveArgumentsToParameters(
- argumentList, parameters, _resolver.errorReporter.reportErrorForNode);
- }
-
/// Given that we are accessing a property of the given [classElement] with the
/// given [propertyName], return the element that represents the property.
Element _resolveElement(
@@ -343,50 +326,6 @@
return null;
}
- /// If there is an extension matching the [receiverType] and defining a
- /// member with the given [name], resolve to the corresponding extension
- /// method. Return a result indicating whether the [node] was resolved and if
- /// not why.
- ResolutionResult _resolveExtension(
- MethodInvocation node,
- Expression receiver,
- DartType receiverType,
- SimpleIdentifier nameNode,
- String name,
- ) {
- var result = _extensionResolver.findExtension(
- receiverType,
- name,
- nameNode,
- );
-
- if (!result.isSingle) {
- _setDynamicResolution(node);
- return result;
- }
-
- var member = _resolver.toLegacyElement(result.getter);
- nameNode.staticElement = member;
-
- if (member.isStatic) {
- _setDynamicResolution(node);
- _resolver.errorReporter.reportErrorForNode(
- StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
- nameNode,
- [name, member.kind.displayName, member.enclosingElement.name]);
- return result;
- }
-
- if (member is PropertyAccessorElement) {
- _rewriteAsFunctionExpressionInvocation(
- node, _elementTypeProvider.getExecutableReturnType(member));
- return result;
- }
-
- _setResolution(node, _elementTypeProvider.getExecutableType(member));
- return result;
- }
-
void _resolveExtensionMember(MethodInvocation node, Identifier receiver,
ExtensionElement extension, SimpleIdentifier nameNode, String name) {
var getter = extension.getGetter(name);
@@ -469,36 +408,13 @@
return;
}
- ResolutionResult result =
- _extensionResolver.findExtension(receiverType, name, nameNode);
- if (result.isSingle) {
- var member = _resolver.toLegacyElement(result.getter);
- nameNode.staticElement = member;
- if (member is PropertyAccessorElement) {
- return _rewriteAsFunctionExpressionInvocation(
- node, _elementTypeProvider.getExecutableReturnType(member));
- }
- return _setResolution(
- node, _elementTypeProvider.getExecutableType(member));
- } else if (result.isAmbiguous) {
- return;
- }
-
- // We can invoke Object methods on Function.
- var member = _inheritance.getMember(
- _resolver.typeProvider.functionType,
- Name(null, name),
- );
- if (member != null) {
- nameNode.staticElement = member;
- return _setResolution(
- node, _elementTypeProvider.getExecutableType(member));
- }
-
- _reportUndefinedMethod(
- node,
- name,
- _resolver.typeProvider.functionType.element,
+ _resolveReceiverType(
+ node: node,
+ receiver: receiver,
+ receiverType: receiverType,
+ nameNode: nameNode,
+ name: name,
+ receiverErrorNode: nameNode,
);
}
@@ -512,53 +428,14 @@
return;
}
- var target = _inheritance.getMember(receiverType, _currentName);
- if (target != null) {
- _resolver.nullableDereferenceVerifier
- .methodInvocation(receiver, receiverType, name);
- target = _resolver.toLegacyElement(target);
- nameNode.staticElement = target;
- if (target is PropertyAccessorElement) {
- return _rewriteAsFunctionExpressionInvocation(
- node, _elementTypeProvider.getExecutableReturnType(target));
- }
- return _setResolution(
- node, _elementTypeProvider.getExecutableType(target));
- }
-
- // Look for an applicable extension.
- var result =
- _resolveExtension(node, receiver, receiverType, nameNode, name);
- if (result.isSingle) {
- return;
- }
-
- // The interface of the receiver does not have an instance member.
- // Try to recover and find a member in the class.
- var targetElement = _lookUpClassMember(receiverType.element, name);
- if (targetElement != null && targetElement.isStatic) {
- nameNode.staticElement = targetElement;
- _setDynamicResolution(node);
- _resolver.errorReporter.reportErrorForNode(
- StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
- nameNode,
- [
- name,
- targetElement.kind.displayName,
- targetElement.enclosingElement.displayName,
- ],
- );
- return;
- }
-
- _setDynamicResolution(node);
- if (result.isNone) {
- _resolver.errorReporter.reportErrorForNode(
- StaticTypeWarningCode.UNDEFINED_METHOD,
- nameNode,
- [name, receiverType.element.displayName],
- );
- }
+ _resolveReceiverType(
+ node: node,
+ receiver: receiver,
+ receiverType: receiverType,
+ nameNode: nameNode,
+ name: name,
+ receiverErrorNode: receiver,
+ );
}
void _resolveReceiverNever(
@@ -643,73 +520,23 @@
return _reportInvocationOfNonFunction(node);
}
- InterfaceType receiverType;
- ClassElement enclosingClass = _resolver.enclosingClass;
- if (enclosingClass == null) {
- if (_resolver.enclosingExtension == null) {
- return _reportUndefinedFunction(node, node.methodName);
- }
- var extendedType =
- _resolveTypeParameter(_resolver.enclosingExtension.extendedType);
- _resolver.nullableDereferenceVerifier.implicitThis(
- nameNode,
- extendedType,
- );
- if (extendedType is InterfaceType) {
- receiverType = extendedType;
- } else if (extendedType is FunctionType) {
- receiverType = _resolver.typeProvider.functionType;
- } else {
- return _reportUndefinedFunction(node, node.methodName);
- }
- enclosingClass = receiverType.element;
+ DartType receiverType;
+ if (_resolver.enclosingClass != null) {
+ receiverType = _resolver.enclosingClass.thisType;
+ } else if (_resolver.enclosingExtension != null) {
+ receiverType = _resolver.enclosingExtension.extendedType;
} else {
- receiverType = enclosingClass.thisType;
- }
- var target = _inheritance.getMember(receiverType, _currentName);
-
- if (target != null) {
- target = _resolver.toLegacyElement(target);
- nameNode.staticElement = target;
- if (target is PropertyAccessorElement) {
- return _rewriteAsFunctionExpressionInvocation(
- node, _elementTypeProvider.getExecutableReturnType(target));
- }
- return _setResolution(
- node, _elementTypeProvider.getExecutableType(target));
+ return _reportUndefinedFunction(node, node.methodName);
}
- var targetElement = _lookUpClassMember(enclosingClass, name);
- if (targetElement != null && targetElement.isStatic) {
- nameNode.staticElement = targetElement;
- _setDynamicResolution(node);
- if (_resolver.enclosingExtension != null) {
- _resolver.errorReporter.reportErrorForNode(
- CompileTimeErrorCode
- .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
- nameNode,
- [targetElement.enclosingElement.displayName]);
- } else {
- _resolver.errorReporter.reportErrorForNode(
- StaticTypeWarningCode
- .UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
- nameNode,
- [targetElement.enclosingElement.displayName]);
- }
- return;
- }
-
- var result = _extensionResolver.findExtension(receiverType, name, nameNode);
- if (result.isSingle) {
- var target = _resolver.toLegacyElement(result.getter);
- if (target != null) {
- nameNode.staticElement = target;
- _setResolution(node, _elementTypeProvider.getExecutableType(target));
- return;
- }
- }
-
- return _reportUndefinedMethod(node, name, enclosingClass);
+ _resolveReceiverType(
+ node: node,
+ receiver: null,
+ receiverType: receiverType,
+ nameNode: nameNode,
+ name: name,
+ receiverErrorNode: nameNode,
+ );
}
void _resolveReceiverPrefix(MethodInvocation node, SimpleIdentifier receiver,
@@ -803,6 +630,62 @@
[name, enclosingClass.displayName]);
}
+ void _resolveReceiverType({
+ @required MethodInvocation node,
+ @required Expression receiver,
+ @required DartType receiverType,
+ @required SimpleIdentifier nameNode,
+ @required String name,
+ @required Expression receiverErrorNode,
+ }) {
+ var result = _resolver.typePropertyResolver.resolve(
+ receiver: receiver,
+ receiverType: receiverType,
+ name: name,
+ receiverErrorNode: receiverErrorNode,
+ nameErrorNode: nameNode,
+ );
+
+ if (result.isAmbiguous) {
+ _setDynamicResolution(node);
+ return;
+ }
+
+ var target = result.getter;
+ if (target != null) {
+ nameNode.staticElement = target;
+
+ if (target.isStatic) {
+ _reportInstanceAccessToStaticMember(
+ nameNode,
+ target,
+ receiver == null,
+ );
+ }
+
+ if (target is PropertyAccessorElement) {
+ return _rewriteAsFunctionExpressionInvocation(
+ node, _elementTypeProvider.getExecutableReturnType(target));
+ }
+ return _setResolution(
+ node, _elementTypeProvider.getExecutableType(target));
+ }
+
+ _setDynamicResolution(node);
+
+ String receiverClassName = '<unknown>';
+ if (receiverType is InterfaceType) {
+ receiverClassName = receiverType.element.name;
+ } else if (receiverType is FunctionType) {
+ receiverClassName = 'Function';
+ }
+ _resolver.errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.UNDEFINED_METHOD,
+ nameNode,
+ [name, receiverClassName],
+ );
+ }
+
void _resolveReceiverTypeLiteral(MethodInvocation node, ClassElement receiver,
SimpleIdentifier nameNode, String name) {
if (node.isCascaded) {
@@ -917,23 +800,7 @@
}
if (type is FunctionType) {
- // TODO(scheglov) Extract this when receiver is already FunctionType?
- var instantiatedType = _instantiateFunctionType(
- type,
- node.typeArguments,
- node.methodName,
- );
- instantiatedType = _toSyntheticFunctionType(instantiatedType);
- node.staticInvokeType = instantiatedType;
- node.staticType = instantiatedType.returnType;
- // TODO(scheglov) too much magic
- node.argumentList.correspondingStaticParameters =
- _resolveArgumentsToParameters(
- node.argumentList,
- instantiatedType.parameters,
- );
-
- _resolveArguments_finishInference(node);
+ _inferenceHelper.resolveMethodInvocation(node: node, rawType: type);
return;
}
@@ -964,30 +831,4 @@
}
return null;
}
-
- /// As an experiment for using synthetic [FunctionType]s, we replace some
- /// function types with the equivalent synthetic function type instance.
- /// The assumption that we try to prove is that only the set of parameters,
- /// with their names, types and kinds is important, but the element that
- /// encloses them is not (`null` for synthetic function types).
- static FunctionType _toSyntheticFunctionType(FunctionType type) {
-// if (type.element is GenericFunctionTypeElement) {
-// var synthetic = FunctionTypeImpl.synthetic(
-// type.returnType,
-// type.typeFormals.map((e) {
-// return TypeParameterElementImpl.synthetic(e.name)..bound = e.bound;
-// }).toList(),
-// type.parameters.map((p) {
-// return ParameterElementImpl.synthetic(
-// p.name,
-// p.type,
-// // ignore: deprecated_member_use_from_same_package
-// p.parameterKind,
-// );
-// }).toList(),
-// );
-// return synthetic;
-// }
- return type;
- }
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
new file mode 100644
index 0000000..4416b89
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -0,0 +1,229 @@
+// 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/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/resolution_result.dart';
+import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/type_system.dart';
+import 'package:analyzer/src/task/strong/checker.dart';
+import 'package:meta/meta.dart';
+
+/// Helper for resolving [PostfixExpression]s.
+class PostfixExpressionResolver {
+ final ResolverVisitor _resolver;
+ final FlowAnalysisHelper _flowAnalysis;
+ final ElementTypeProvider _elementTypeProvider;
+ final TypePropertyResolver _typePropertyResolver;
+ final InvocationInferenceHelper _inferenceHelper;
+
+ PostfixExpressionResolver({
+ @required ResolverVisitor resolver,
+ @required FlowAnalysisHelper flowAnalysis,
+ @required ElementTypeProvider elementTypeProvider,
+ }) : _resolver = resolver,
+ _flowAnalysis = flowAnalysis,
+ _elementTypeProvider = elementTypeProvider,
+ _typePropertyResolver = resolver.typePropertyResolver,
+ _inferenceHelper = resolver.inferenceHelper;
+
+ ErrorReporter get _errorReporter => _resolver.errorReporter;
+
+ bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
+
+ TypeSystemImpl get _typeSystem => _resolver.typeSystem;
+
+ void resolve(PostfixExpressionImpl node) {
+ if (node.operator.type == TokenType.BANG) {
+ _resolveNullCheck(node);
+ return;
+ }
+
+ node.operand.accept(_resolver);
+
+ var receiverType = getReadType(
+ node.operand,
+ elementTypeProvider: _elementTypeProvider,
+ );
+
+ _resolve1(node, receiverType);
+ _resolve2(node, receiverType);
+ }
+
+ /// Check that the result [type] of a prefix or postfix `++` or `--`
+ /// expression is assignable to the write type of the [operand].
+ ///
+ /// TODO(scheglov) this is duplicate
+ void _checkForInvalidAssignmentIncDec(
+ AstNode node, Expression operand, DartType type) {
+ var operandWriteType = _getWriteType(operand);
+ if (!_typeSystem.isAssignableTo(type, operandWriteType)) {
+ _resolver.errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.INVALID_ASSIGNMENT,
+ node,
+ [type, operandWriteType],
+ );
+ }
+ }
+
+ /// Compute the static return type of the method or function represented by the given element.
+ ///
+ /// @param element the element representing the method or function invoked by the given node
+ /// @return the static return type that was computed
+ ///
+ /// TODO(scheglov) this is duplicate
+ DartType _computeStaticReturnType(Element element) {
+ if (element is PropertyAccessorElement) {
+ //
+ // This is a function invocation expression disguised as something else.
+ // We are invoking a getter and then invoking the returned function.
+ //
+ FunctionType propertyType =
+ _elementTypeProvider.getExecutableType(element);
+ if (propertyType != null) {
+ return _resolver.inferenceHelper.computeInvokeReturnType(
+ propertyType.returnType,
+ isNullAware: false);
+ }
+ } else if (element is ExecutableElement) {
+ return _resolver.inferenceHelper.computeInvokeReturnType(
+ _elementTypeProvider.getExecutableType(element),
+ isNullAware: false);
+ }
+ return DynamicTypeImpl.instance;
+ }
+
+ /// Return the name of the method invoked by the given postfix [expression].
+ String _getPostfixOperator(PostfixExpression expression) {
+ if (expression.operator.type == TokenType.PLUS_PLUS) {
+ return TokenType.PLUS.lexeme;
+ } else if (expression.operator.type == TokenType.MINUS_MINUS) {
+ return TokenType.MINUS.lexeme;
+ } else {
+ throw UnsupportedError(
+ 'Unsupported postfix operator ${expression.operator.lexeme}');
+ }
+ }
+
+ DartType _getWriteType(Expression node) {
+ if (node is SimpleIdentifier) {
+ var element = node.staticElement;
+ if (element is PromotableElement) {
+ return _elementTypeProvider.getVariableType(element);
+ }
+ }
+ return node.staticType;
+ }
+
+ void _resolve1(PostfixExpression node, DartType receiverType) {
+ Expression operand = node.operand;
+
+ if (identical(receiverType, NeverTypeImpl.instance)) {
+ _resolver.errorReporter.reportErrorForNode(
+ StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ operand,
+ );
+ return;
+ }
+
+ String methodName = _getPostfixOperator(node);
+ var result = _typePropertyResolver.resolve(
+ receiver: operand,
+ receiverType: receiverType,
+ name: methodName,
+ receiverErrorNode: operand,
+ nameErrorNode: operand,
+ );
+ node.staticElement = result.getter;
+ if (_shouldReportInvalidMember(receiverType, result)) {
+ if (operand is SuperExpression) {
+ _errorReporter.reportErrorForToken(
+ StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
+ node.operator,
+ [methodName, receiverType],
+ );
+ } else {
+ _errorReporter.reportErrorForToken(
+ StaticTypeWarningCode.UNDEFINED_OPERATOR,
+ node.operator,
+ [methodName, receiverType],
+ );
+ }
+ }
+ }
+
+ void _resolve2(PostfixExpression node, DartType receiverType) {
+ Expression operand = node.operand;
+
+ if (identical(receiverType, NeverTypeImpl.instance)) {
+ _inferenceHelper.recordStaticType(node, NeverTypeImpl.instance);
+ } else {
+ DartType operatorReturnType;
+ if (receiverType.isDartCoreInt) {
+ // No need to check for `intVar++`, the result is `int`.
+ operatorReturnType = receiverType;
+ } else {
+ var operatorElement = node.staticElement;
+ operatorReturnType = _computeStaticReturnType(operatorElement);
+ _checkForInvalidAssignmentIncDec(node, operand, operatorReturnType);
+ }
+ if (operand is SimpleIdentifier) {
+ var element = operand.staticElement;
+ if (element is PromotableElement) {
+ _flowAnalysis?.flow?.write(element, operatorReturnType);
+ }
+ }
+ }
+
+ _inferenceHelper.recordStaticType(node, receiverType);
+ }
+
+ void _resolveNullCheck(PostfixExpressionImpl node) {
+ var operand = node.operand;
+
+ var contextType = InferenceContext.getContext(node);
+ if (contextType != null) {
+ if (_isNonNullableByDefault) {
+ contextType = _typeSystem.makeNullable(contextType);
+ }
+ InferenceContext.setType(operand, contextType);
+ }
+
+ operand.accept(_resolver);
+
+ var operandType = getReadType(
+ operand,
+ elementTypeProvider: _elementTypeProvider,
+ );
+
+ var type = _typeSystem.promoteToNonNull(operandType);
+ _inferenceHelper.recordStaticType(node, type);
+
+ _flowAnalysis?.flow?.nonNullAssert_end(operand);
+ }
+
+ /// Return `true` if we should report an error for the lookup [result] on
+ /// the [type].
+ ///
+ /// TODO(scheglov) this is duplicate
+ bool _shouldReportInvalidMember(DartType type, ResolutionResult result) {
+ if (result.isNone && type != null && !type.isDynamic) {
+ if (_isNonNullableByDefault && _typeSystem.isPotentiallyNullable(type)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 6e4700a..1ad1850 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -52,16 +52,14 @@
var operand = node.operand;
if (operator == TokenType.BANG) {
- InferenceContext.setType(operand, _typeProvider.boolType);
+ _resolveNegation(node, operand);
+ return;
}
+
operand.accept(_resolver);
_resolve1(node);
_resolve2(node);
-
- if (operator == TokenType.BANG) {
- _flowAnalysis?.flow?.logicalNot_end(node, operand);
- }
}
/// Check that the result [type] of a prefix or postfix `++` or `--`
@@ -226,9 +224,7 @@
void _resolve2(PrefixExpressionImpl node) {
TokenType operator = node.operator.type;
- if (operator == TokenType.BANG) {
- _recordStaticType(node, _nonNullable(_typeProvider.boolType));
- } else if (identical(node.operand.staticType, NeverTypeImpl.instance)) {
+ if (identical(node.operand.staticType, NeverTypeImpl.instance)) {
_recordStaticType(node, NeverTypeImpl.instance);
} else {
// The other cases are equivalent to invoking a method.
@@ -255,6 +251,16 @@
}
}
+ void _resolveNegation(PrefixExpressionImpl node, Expression operand) {
+ InferenceContext.setType(operand, _typeProvider.boolType);
+
+ operand.accept(_resolver);
+
+ _recordStaticType(node, _nonNullable(_typeProvider.boolType));
+
+ _flowAnalysis?.flow?.logicalNot_end(node, operand);
+ }
+
/// If the given [type] is a type parameter, resolve it to the type that should
/// be used when looking up members. Otherwise, return the original type.
///
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 7cd588e..885602f 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -206,16 +206,6 @@
}
@override
- void visitBinaryExpression(BinaryExpression node) {
- Token operator = node.operator;
- if (operator.isUserDefinableOperator) {
- _resolveBinaryExpression(node, operator.lexeme);
- } else if (operator.type == TokenType.BANG_EQ) {
- _resolveBinaryExpression(node, TokenType.EQ_EQ.lexeme);
- }
- }
-
- @override
void visitBreakStatement(BreakStatement node) {
node.target = _lookupBreakOrContinueTarget(node, node.label, false);
}
@@ -549,50 +539,6 @@
}
@override
- void visitPostfixExpression(PostfixExpression node) {
- Expression operand = node.operand;
- if (node.operator.type == TokenType.BANG) {
- // Null-assertion operator (`!`). There's nothing to do, since this is a
- // built-in operation (there's no associated operator declaration).
- return;
- }
- DartType staticType = _getStaticType(operand);
-
- if (identical(staticType, NeverTypeImpl.instance)) {
- _resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
- operand,
- );
- return;
- }
-
- String methodName = _getPostfixOperator(node);
- var result = _typePropertyResolver.resolve(
- receiver: operand,
- receiverType: staticType,
- name: methodName,
- receiverErrorNode: operand,
- nameErrorNode: operand,
- );
- node.staticElement = result.getter;
- if (_shouldReportInvalidMember(staticType, result)) {
- if (operand is SuperExpression) {
- _errorReporter.reportErrorForToken(
- StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
- node.operator,
- [methodName, staticType],
- );
- } else {
- _errorReporter.reportErrorForToken(
- StaticTypeWarningCode.UNDEFINED_OPERATOR,
- node.operator,
- [methodName, staticType],
- );
- }
- }
- }
-
- @override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
SimpleIdentifier prefix = node.prefix;
SimpleIdentifier identifier = node.identifier;
@@ -1046,20 +992,6 @@
}
/**
- * Return the name of the method invoked by the given postfix [expression].
- */
- String _getPostfixOperator(PostfixExpression expression) {
- if (expression.operator.type == TokenType.PLUS_PLUS) {
- return TokenType.PLUS.lexeme;
- } else if (expression.operator.type == TokenType.MINUS_MINUS) {
- return TokenType.MINUS.lexeme;
- } else {
- throw UnsupportedError(
- 'Unsupported postfix operator ${expression.operator.lexeme}');
- }
- }
-
- /**
* Return the static type of the given [expression] that is to be used for
* type analysis.
*/
@@ -1340,61 +1272,6 @@
argumentList, parameters, _errorReporter.reportErrorForNode);
}
- void _resolveBinaryExpression(BinaryExpression node, String methodName) {
- Expression leftOperand = node.leftOperand;
-
- if (leftOperand is ExtensionOverride) {
- ExtensionElement extension = leftOperand.extensionName.staticElement;
- MethodElement member = extension.getMethod(methodName);
- if (member == null) {
- _errorReporter.reportErrorForToken(
- CompileTimeErrorCode.UNDEFINED_EXTENSION_OPERATOR,
- node.operator,
- [methodName, extension.name],
- );
- }
- node.staticElement = member;
- return;
- }
-
- DartType leftType = _getStaticType(leftOperand);
-
- if (identical(leftType, NeverTypeImpl.instance)) {
- _resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
- leftOperand,
- );
- return;
- }
-
- ResolutionResult result = _typePropertyResolver.resolve(
- receiver: leftOperand,
- receiverType: leftType,
- name: methodName,
- receiverErrorNode: leftOperand,
- nameErrorNode: node,
- );
-
- node.staticElement = result.getter;
- node.staticInvokeType =
- _elementTypeProvider.safeExecutableType(result.getter);
- if (_shouldReportInvalidMember(leftType, result)) {
- if (leftOperand is SuperExpression) {
- _errorReporter.reportErrorForToken(
- StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
- node.operator,
- [methodName, leftType],
- );
- } else {
- _errorReporter.reportErrorForToken(
- StaticTypeWarningCode.UNDEFINED_OPERATOR,
- node.operator,
- [methodName, leftType],
- );
- }
- }
- }
-
/**
* Resolve the names in the given [combinators] in the scope of the given
* [library].
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index a1c4b3a..50f345c 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -23,11 +23,13 @@
import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/resolver/binary_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/dart/resolver/function_expression_invocation_resolver.dart';
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
+import 'package:analyzer/src/dart/resolver/postfix_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/prefix_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
@@ -207,7 +209,9 @@
/// Helper for resolving [ListLiteral] and [SetOrMapLiteral].
TypedLiteralResolver _typedLiteralResolver;
+ BinaryExpressionResolver _binaryExpressionResolver;
FunctionExpressionInvocationResolver _functionExpressionInvocationResolver;
+ PostfixExpressionResolver _postfixExpressionResolver;
PrefixExpressionResolver _prefixExpressionResolver;
InvocationInferenceHelper inferenceHelper;
@@ -329,17 +333,29 @@
this.extensionResolver = ExtensionMemberResolver(this);
this.typePropertyResolver = TypePropertyResolver(this);
this.inferenceHelper = InvocationInferenceHelper(
+ resolver: this,
definingLibrary: definingLibrary,
elementTypeProvider: _elementTypeProvider,
flowAnalysis: _flowAnalysis,
errorReporter: errorReporter,
typeSystem: typeSystem,
);
+ this._binaryExpressionResolver = BinaryExpressionResolver(
+ resolver: this,
+ promoteManager: _promoteManager,
+ flowAnalysis: _flowAnalysis,
+ elementTypeProvider: _elementTypeProvider,
+ );
this._functionExpressionInvocationResolver =
FunctionExpressionInvocationResolver(
resolver: this,
elementTypeProvider: _elementTypeProvider,
);
+ this._postfixExpressionResolver = PostfixExpressionResolver(
+ resolver: this,
+ flowAnalysis: _flowAnalysis,
+ elementTypeProvider: _elementTypeProvider,
+ );
this._prefixExpressionResolver = PrefixExpressionResolver(
resolver: this,
flowAnalysis: _flowAnalysis,
@@ -641,92 +657,7 @@
@override
void visitBinaryExpression(BinaryExpression node) {
- TokenType operator = node.operator.type;
- Expression left = node.leftOperand;
- Expression right = node.rightOperand;
- var flow = _flowAnalysis?.flow;
-
- if (operator == TokenType.AMPERSAND_AMPERSAND) {
- InferenceContext.setType(left, typeProvider.boolType);
- InferenceContext.setType(right, typeProvider.boolType);
-
- // TODO(scheglov) Do we need these checks for null?
- left?.accept(this);
-
- if (_flowAnalysis != null) {
- flow?.logicalBinaryOp_rightBegin(left, isAnd: true);
- _flowAnalysis.checkUnreachableNode(right);
- right.accept(this);
- flow?.logicalBinaryOp_end(node, right, isAnd: true);
- } else {
- _promoteManager.visitBinaryExpression_and_rhs(
- left,
- right,
- () {
- right.accept(this);
- },
- );
- }
-
- node.accept(elementResolver);
- } else if (operator == TokenType.BAR_BAR) {
- InferenceContext.setType(left, typeProvider.boolType);
- InferenceContext.setType(right, typeProvider.boolType);
-
- left?.accept(this);
-
- flow?.logicalBinaryOp_rightBegin(left, isAnd: false);
- _flowAnalysis?.checkUnreachableNode(right);
- right.accept(this);
- flow?.logicalBinaryOp_end(node, right, isAnd: false);
-
- node.accept(elementResolver);
- } else if (operator == TokenType.BANG_EQ || operator == TokenType.EQ_EQ) {
- left.accept(this);
- _flowAnalysis?.flow?.equalityOp_rightBegin(left);
- right.accept(this);
- node.accept(elementResolver);
- _flowAnalysis?.flow?.equalityOp_end(node, right,
- notEqual: operator == TokenType.BANG_EQ);
- } else {
- if (operator == TokenType.QUESTION_QUESTION) {
- InferenceContext.setTypeFromNode(left, node);
- }
- left?.accept(this);
-
- // Call ElementResolver.visitBinaryExpression to resolve the user-defined
- // operator method, if applicable.
- node.accept(elementResolver);
-
- if (operator == TokenType.QUESTION_QUESTION) {
- // Set the right side, either from the context, or using the information
- // from the left side if it is more precise.
- DartType contextType = InferenceContext.getContext(node);
- DartType leftType = left?.staticType;
- if (contextType == null || contextType.isDynamic) {
- contextType = leftType;
- }
- InferenceContext.setType(right, contextType);
- } else {
- var invokeType = node.staticInvokeType;
- if (invokeType != null && invokeType.parameters.isNotEmpty) {
- // If this is a user-defined operator, set the right operand context
- // using the operator method's parameter type.
- var rightParam = invokeType.parameters[0];
- InferenceContext.setType(
- right, _elementTypeProvider.getVariableType(rightParam));
- }
- }
-
- if (operator == TokenType.QUESTION_QUESTION) {
- flow?.ifNullExpression_rightBegin(node.leftOperand);
- right.accept(this);
- flow?.ifNullExpression_end();
- } else {
- right?.accept(this);
- }
- }
- node.accept(typeAnalyzer);
+ _binaryExpressionResolver.resolve(node);
}
@override
@@ -1583,12 +1514,7 @@
@override
void visitPostfixExpression(PostfixExpression node) {
- super.visitPostfixExpression(node);
-
- var operator = node.operator.type;
- if (operator == TokenType.BANG) {
- _flowAnalysis?.flow?.nonNullAssert_end(node.operand);
- }
+ _postfixExpressionResolver.resolve(node);
}
@override
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 2bad223..7114129 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -340,83 +340,6 @@
}
/**
- * The Dart Language Specification, 12.20: <blockquote>The static type of a logical boolean
- * expression is `bool`.</blockquote>
- *
- * The Dart Language Specification, 12.21:<blockquote>A bitwise expression of the form
- * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocation
- * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A bitwise expression of the form <i>super op
- * e<sub>2</sub></i> is equivalent to the method invocation
- * <i>super.op(e<sub>2</sub>)</i>.</blockquote>
- *
- * The Dart Language Specification, 12.22: <blockquote>The static type of an equality expression
- * is `bool`.</blockquote>
- *
- * The Dart Language Specification, 12.23: <blockquote>A relational expression of the form
- * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocation
- * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A relational expression of the form <i>super op
- * e<sub>2</sub></i> is equivalent to the method invocation
- * <i>super.op(e<sub>2</sub>)</i>.</blockquote>
- *
- * The Dart Language Specification, 12.24: <blockquote>A shift expression of the form
- * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocation
- * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A shift expression of the form <i>super op
- * e<sub>2</sub></i> is equivalent to the method invocation
- * <i>super.op(e<sub>2</sub>)</i>.</blockquote>
- *
- * The Dart Language Specification, 12.25: <blockquote>An additive expression of the form
- * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocation
- * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. An additive expression of the form <i>super op
- * e<sub>2</sub></i> is equivalent to the method invocation
- * <i>super.op(e<sub>2</sub>)</i>.</blockquote>
- *
- * The Dart Language Specification, 12.26: <blockquote>A multiplicative expression of the form
- * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocation
- * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A multiplicative expression of the form <i>super op
- * e<sub>2</sub></i> is equivalent to the method invocation
- * <i>super.op(e<sub>2</sub>)</i>.</blockquote>
- */
- @override
- void visitBinaryExpression(BinaryExpression node) {
- if (node.operator.type == TokenType.QUESTION_QUESTION) {
- if (_isNonNullableByDefault) {
- // The static type of a compound assignment using ??= with NNBD is the
- // least upper bound of the static types of the LHS and RHS after
- // promoting the LHS/ to non-null (as we know its value will not be used
- // if null)
- _analyzeLeastUpperBoundTypes(
- node,
- _typeSystem.promoteToNonNull(
- _getExpressionType(node.leftOperand, read: true)),
- _getExpressionType(node.rightOperand, read: true));
- } else {
- // Without NNBD, evaluation of an if-null expression e of the form
- // e1 ?? e2 is equivalent to the evaluation of the expression
- // ((x) => x == null ? e2 : x)(e1). The static type of e is the least
- // upper bound of the static type of e1 and the static type of e2.
- _analyzeLeastUpperBound(node, node.leftOperand, node.rightOperand);
- }
- return;
- }
-
- if (identical(node.leftOperand.staticType, NeverTypeImpl.instance)) {
- _recordStaticType(node, NeverTypeImpl.instance);
- return;
- }
-
- DartType staticType = node.staticInvokeType?.returnType ?? _dynamicType;
- if (node.leftOperand is! ExtensionOverride) {
- staticType = _typeSystem.refineBinaryExpressionType(
- node.leftOperand.staticType,
- node.operator.type,
- node.rightOperand.staticType,
- staticType,
- );
- }
- _recordStaticType(node, staticType);
- }
-
- /**
* The Dart Language Specification, 12.4: <blockquote>The static type of a boolean literal is
* bool.</blockquote>
*/
@@ -636,62 +559,6 @@
}
/**
- * The Dart Language Specification, 12.28: <blockquote>A postfix expression of the form
- * <i>v++</i>, where <i>v</i> is an identifier, is equivalent to <i>(){var r = v; v = r + 1;
- * return r}()</i>.
- *
- * A postfix expression of the form <i>C.v++</i> is equivalent to <i>(){var r = C.v; C.v = r + 1;
- * return r}()</i>.
- *
- * A postfix expression of the form <i>e1.v++</i> is equivalent to <i>(x){var r = x.v; x.v = r +
- * 1; return r}(e1)</i>.
- *
- * A postfix expression of the form <i>e1[e2]++</i> is equivalent to <i>(a, i){var r = a[i]; a[i]
- * = r + 1; return r}(e1, e2)</i>
- *
- * A postfix expression of the form <i>v--</i>, where <i>v</i> is an identifier, is equivalent to
- * <i>(){var r = v; v = r - 1; return r}()</i>.
- *
- * A postfix expression of the form <i>C.v--</i> is equivalent to <i>(){var r = C.v; C.v = r - 1;
- * return r}()</i>.
- *
- * A postfix expression of the form <i>e1.v--</i> is equivalent to <i>(x){var r = x.v; x.v = r -
- * 1; return r}(e1)</i>.
- *
- * A postfix expression of the form <i>e1[e2]--</i> is equivalent to <i>(a, i){var r = a[i]; a[i]
- * = r - 1; return r}(e1, e2)</i></blockquote>
- */
- @override
- void visitPostfixExpression(PostfixExpression node) {
- Expression operand = node.operand;
- TypeImpl staticType = _getStaticType(operand, read: true);
-
- if (node.operator.type == TokenType.BANG) {
- staticType = _typeSystem.promoteToNonNull(staticType);
- } else if (identical(staticType, NeverTypeImpl.instance)) {
- _recordStaticType(node, NeverTypeImpl.instance);
- } else {
- DartType operatorReturnType;
- if (staticType.isDartCoreInt) {
- // No need to check for `intVar++`, the result is `int`.
- operatorReturnType = staticType;
- } else {
- var operatorElement = node.staticElement;
- operatorReturnType = _computeStaticReturnType(operatorElement);
- _checkForInvalidAssignmentIncDec(node, operand, operatorReturnType);
- }
- if (operand is SimpleIdentifier) {
- var element = operand.staticElement;
- if (element is PromotableElement) {
- _flowAnalysis?.flow?.write(element, operatorReturnType);
- }
- }
- }
-
- _recordStaticType(node, staticType);
- }
-
- /**
* See [visitSimpleIdentifier].
*/
@override
@@ -1004,20 +871,6 @@
_recordStaticType(node, staticType);
}
- /// Check that the result [type] of a prefix or postfix `++` or `--`
- /// expression is assignable to the write type of the [operand].
- void _checkForInvalidAssignmentIncDec(
- AstNode node, Expression operand, DartType type) {
- var operandWriteType = _getStaticType(operand);
- if (!_typeSystem.isAssignableTo(type, operandWriteType)) {
- _resolver.errorReporter.reportErrorForNode(
- StaticTypeWarningCode.INVALID_ASSIGNMENT,
- node,
- [type, operandWriteType],
- );
- }
- }
-
/**
* Given a function body and its return type, compute the return type of
* the entire function, taking into account whether the function body
@@ -1044,33 +897,6 @@
}
/**
- * Compute the static return type of the method or function represented by the given element.
- *
- * @param element the element representing the method or function invoked by the given node
- * @return the static return type that was computed
- */
- DartType _computeStaticReturnType(Element element) {
- if (element is PropertyAccessorElement) {
- //
- // This is a function invocation expression disguised as something else.
- // We are invoking a getter and then invoking the returned function.
- //
- FunctionType propertyType =
- _elementTypeProvider.getExecutableType(element);
- if (propertyType != null) {
- return _resolver.inferenceHelper.computeInvokeReturnType(
- propertyType.returnType,
- isNullAware: false);
- }
- } else if (element is ExecutableElement) {
- return _resolver.inferenceHelper.computeInvokeReturnType(
- _elementTypeProvider.getExecutableType(element),
- isNullAware: false);
- }
- return _dynamicType;
- }
-
- /**
* Given a function declaration, compute the return static type of the function. The return type
* of functions with a block body is `dynamicType`, with an expression body it is the type
* of the expression.
diff --git a/pkg/analyzer/lib/src/lint/analysis.dart b/pkg/analyzer/lib/src/lint/analysis.dart
index e85f5b6..53ea208 100644
--- a/pkg/analyzer/lib/src/lint/analysis.dart
+++ b/pkg/analyzer/lib/src/lint/analysis.dart
@@ -141,8 +141,11 @@
if (options.packageRootPath != null) {
builder.builderOptions.defaultPackagesDirectoryPath =
options.packageRootPath;
- Map<String, List<Folder>> packageMap =
- builder.convertPackagesToMap(builder.createPackageMap(null));
+ var packages = builder.createPackageMap(null);
+ var packageMap = <String, List<Folder>>{};
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
resolvers.add(PackageMapUriResolver(resourceProvider, packageMap));
}
diff --git a/pkg/analyzer/lib/src/workspace/basic.dart b/pkg/analyzer/lib/src/workspace/basic.dart
index 0225481..13455c9 100644
--- a/pkg/analyzer/lib/src/workspace/basic.dart
+++ b/pkg/analyzer/lib/src/workspace/basic.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/workspace/simple.dart';
import 'package:analyzer/src/workspace/workspace.dart';
@@ -23,8 +22,10 @@
BasicWorkspacePackage _theOnlyPackage;
BasicWorkspace._(
- ResourceProvider provider, String root, ContextBuilder builder)
- : super(provider, root, builder);
+ ResourceProvider provider,
+ Map<String, List<Folder>> packageMap,
+ String root,
+ ) : super(provider, packageMap, root);
@override
WorkspacePackage findPackageFor(String filePath) {
@@ -45,12 +46,15 @@
* (or [path]'s parent if [path] points to a file).
*/
static BasicWorkspace find(
- ResourceProvider provider, String path, ContextBuilder builder) {
+ ResourceProvider provider,
+ Map<String, List<Folder>> packageMap,
+ String path,
+ ) {
Resource resource = provider.getResource(path);
if (resource is File) {
path = resource.parent.path;
}
- return BasicWorkspace._(provider, path, builder);
+ return BasicWorkspace._(provider, packageMap, path);
}
}
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index 0b2c7c9..9e42c63 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -200,9 +200,6 @@
bool get isBazel => true;
@override
- Map<String, List<Folder>> get packageMap => null;
-
- @override
UriResolver get packageUriResolver => BazelPackageUriResolver(this);
@override
diff --git a/pkg/analyzer/lib/src/workspace/gn.dart b/pkg/analyzer/lib/src/workspace/gn.dart
index 0f91f05..e0aae5f 100644
--- a/pkg/analyzer/lib/src/workspace/gn.dart
+++ b/pkg/analyzer/lib/src/workspace/gn.dart
@@ -2,21 +2,18 @@
// 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 'dart:core';
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/source/package_map_resolver.dart';
import 'package:analyzer/src/summary/package_bundle_reader.dart';
-import 'package:analyzer/src/util/uri.dart';
import 'package:analyzer/src/workspace/workspace.dart';
-import 'package:package_config/packages.dart';
-import 'package:package_config/packages_file.dart';
-import 'package:package_config/src/packages_impl.dart';
+import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
/**
@@ -48,35 +45,18 @@
final String root;
/**
- * The paths to the .packages files.
- */
- final List<String> _packagesFilePaths;
-
- /**
- * The map of package locations indexed by package name.
- *
- * This is a cached field.
+ * The map from a package name to the list of its `lib/` folders.
*/
Map<String, List<Folder>> _packageMap;
- /**
- * The package location strategy.
- *
- * This is a cached field.
- */
- Packages _packages;
+ GnWorkspace._(this.provider, this.root, this._packageMap);
- GnWorkspace._(this.provider, this.root, this._packagesFilePaths);
-
- @override
- Map<String, List<Folder>> get packageMap =>
- _packageMap ??= _convertPackagesToMap(packages);
-
- Packages get packages => _packages ??= _createPackages();
+ @visibleForTesting
+ Map<String, List<Folder>> get packageMap => _packageMap;
@override
UriResolver get packageUriResolver =>
- PackageMapUriResolver(provider, packageMap);
+ PackageMapUriResolver(provider, _packageMap);
@override
SourceFactory createSourceFactory(DartSdk sdk, SummaryDataStore summaryData) {
@@ -133,65 +113,6 @@
}
/**
- * Creates an alternate representation for available packages.
- */
- Map<String, List<Folder>> _convertPackagesToMap(Packages packages) {
- Map<String, List<Folder>> folderMap = HashMap<String, List<Folder>>();
- if (packages != null && packages != Packages.noPackages) {
- var pathContext = provider.pathContext;
- packages.asMap().forEach((String packageName, Uri uri) {
- String filePath = fileUriToNormalizedPath(pathContext, uri);
- folderMap[packageName] = [provider.getFolder(filePath)];
- });
- }
- return folderMap;
- }
-
- /**
- * Loads the packages from the .packages file.
- */
- Packages _createPackages() {
- Map<String, Uri> map = _packagesFilePaths.map((String filePath) {
- File configFile = provider.getFile(filePath);
- List<int> bytes = configFile.readAsBytesSync();
- return parse(bytes, configFile.toUri());
- }).reduce((mapOne, mapTwo) {
- mapOne.addAll(mapTwo);
- return mapOne;
- });
- _resolveSymbolicLinks(map);
- return MapPackages(map);
- }
-
- /**
- * Resolve any symbolic links encoded in the path to the given [folder].
- */
- String _resolveSymbolicLink(Folder folder) {
- try {
- return folder.resolveSymbolicLinksSync().path;
- } on FileSystemException {
- return folder.path;
- }
- }
-
- /**
- * Resolve any symbolic links encoded in the URI's in the given [map] by
- * replacing the values in the map.
- */
- void _resolveSymbolicLinks(Map<String, Uri> map) {
- path.Context pathContext = provider.pathContext;
- for (String packageName in map.keys) {
- String filePath = fileUriToNormalizedPath(pathContext, map[packageName]);
- Folder folder = provider.getFolder(filePath);
- String folderPath = _resolveSymbolicLink(folder);
- // Add a '.' so that the URI is suitable for resolving relative URI's
- // against it.
- String uriPath = pathContext.join(folderPath, '.');
- map[packageName] = pathContext.toUri(uriPath);
- }
- }
-
- /**
* Find the GN workspace that contains the given [filePath].
*
* Return `null` if a workspace could not be found. For a workspace to be
@@ -213,12 +134,21 @@
if (folder.getChildAssumingFolder(_jiriRootName).exists) {
// Found the .jiri_root file, must be a non-git workspace.
String root = folder.path;
- List<String> packagesFiles =
- _findPackagesFile(provider, root, filePath);
+
+ var packagesFiles = _findPackagesFile(provider, root, filePath);
if (packagesFiles.isEmpty) {
return null;
}
- return GnWorkspace._(provider, root, packagesFiles);
+
+ var packageMap = <String, List<Folder>>{};
+ for (var packagesFile in packagesFiles) {
+ var packages = parseDotPackagesFile(provider, packagesFile);
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
+ }
+
+ return GnWorkspace._(provider, root, packageMap);
}
// Go up a folder.
@@ -235,7 +165,7 @@
* target. For a complete view of the package, all of these files need to be
* taken into account.
*/
- static List<String> _findPackagesFile(
+ static List<File> _findPackagesFile(
ResourceProvider provider,
String root,
String filePath,
@@ -244,18 +174,17 @@
String sourceDirectory = pathContext.relative(filePath, from: root);
Folder outDirectory = _getOutDirectory(root, provider);
if (outDirectory == null) {
- return const <String>[];
+ return const <File>[];
}
Folder genDir = outDirectory.getChildAssumingFolder(
pathContext.join('dartlang', 'gen', sourceDirectory));
if (!genDir.exists) {
- return const <String>[];
+ return const <File>[];
}
return genDir
.getChildren()
.whereType<File>()
.where((File file) => pathContext.extension(file.path) == '.packages')
- .map((File file) => file.path)
.toList();
}
diff --git a/pkg/analyzer/lib/src/workspace/package_build.dart b/pkg/analyzer/lib/src/workspace/package_build.dart
index 875eb3c..92aa30e 100644
--- a/pkg/analyzer/lib/src/workspace/package_build.dart
+++ b/pkg/analyzer/lib/src/workspace/package_build.dart
@@ -5,7 +5,6 @@
import 'dart:core';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -153,6 +152,11 @@
final ResourceProvider provider;
/**
+ * The map from a package name to the list of its `lib/` folders.
+ */
+ final Map<String, List<Folder>> _packageMap;
+
+ /**
* The absolute workspace root path (the directory containing the `.dart_tool`
* directory).
*/
@@ -165,22 +169,6 @@
*/
final String projectPackageName;
- final ContextBuilder _builder;
-
- /**
- * The map of package locations indexed by package name.
- *
- * This is a cached field.
- */
- Map<String, List<Folder>> _packageMap;
-
- /**
- * The package location strategy.
- *
- * This is a cached field.
- */
- Packages _packages;
-
/**
* The singular package in this workspace.
*
@@ -189,22 +177,11 @@
PackageBuildWorkspacePackage _theOnlyPackage;
PackageBuildWorkspace._(
- this.provider, this.root, this.projectPackageName, this._builder);
-
- @override
- Map<String, List<Folder>> get packageMap {
- _packageMap ??= _builder.convertPackagesToMap(packages);
- return _packageMap;
- }
-
- Packages get packages {
- _packages ??= _builder.createPackageMap(root);
- return _packages;
- }
+ this.provider, this._packageMap, this.root, this.projectPackageName);
@override
UriResolver get packageUriResolver => PackageBuildPackageUriResolver(
- this, PackageMapUriResolver(provider, packageMap));
+ this, PackageMapUriResolver(provider, _packageMap));
/**
* For some package file, which may or may not be a package source (it could
@@ -216,7 +193,7 @@
* to the project root.
*/
File builtFile(String builtPath, String packageName) {
- if (!packageMap.containsKey(packageName)) {
+ if (!_packageMap.containsKey(packageName)) {
return null;
}
path.Context context = provider.pathContext;
@@ -295,8 +272,8 @@
*
* Return `null` if the filePath is not in a package:build workspace.
*/
- static PackageBuildWorkspace find(
- ResourceProvider provider, String filePath, ContextBuilder builder) {
+ static PackageBuildWorkspace find(ResourceProvider provider,
+ Map<String, List<Folder>> packageMap, String filePath) {
Folder folder = provider.getFolder(filePath);
while (true) {
Folder parent = folder.parent;
@@ -316,7 +293,7 @@
try {
final yaml = loadYaml(pubspec.readAsStringSync());
return PackageBuildWorkspace._(
- provider, folder.path, yaml['name'], builder);
+ provider, packageMap, folder.path, yaml['name']);
} catch (_) {}
}
diff --git a/pkg/analyzer/lib/src/workspace/pub.dart b/pkg/analyzer/lib/src/workspace/pub.dart
index cbec8ab..6cd27ee 100644
--- a/pkg/analyzer/lib/src/workspace/pub.dart
+++ b/pkg/analyzer/lib/src/workspace/pub.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/workspace/simple.dart';
import 'package:analyzer/src/workspace/workspace.dart';
@@ -19,8 +18,11 @@
/// Each Pub workspace is itself one package.
PubWorkspacePackage _theOnlyPackage;
- PubWorkspace._(ResourceProvider provider, String root, ContextBuilder builder)
- : super(provider, root, builder);
+ PubWorkspace._(
+ ResourceProvider provider,
+ Map<String, List<Folder>> packageMap,
+ String root,
+ ) : super(provider, packageMap, root);
@override
WorkspacePackage findPackageFor(String filePath) {
@@ -35,7 +37,10 @@
/// Find the pub workspace that contains the given [path].
static PubWorkspace find(
- ResourceProvider provider, String filePath, ContextBuilder builder) {
+ ResourceProvider provider,
+ Map<String, List<Folder>> packageMap,
+ String filePath,
+ ) {
Resource resource = provider.getResource(filePath);
if (resource is File) {
filePath = resource.parent.path;
@@ -50,7 +55,7 @@
if (folder.getChildAssumingFile(_pubspecName).exists) {
// Found the pubspec.yaml file; this is our root.
String root = folder.path;
- return PubWorkspace._(provider, root, builder);
+ return PubWorkspace._(provider, packageMap, root);
}
// Go up a folder.
diff --git a/pkg/analyzer/lib/src/workspace/simple.dart b/pkg/analyzer/lib/src/workspace/simple.dart
index bddf28b..ba316fb 100644
--- a/pkg/analyzer/lib/src/workspace/simple.dart
+++ b/pkg/analyzer/lib/src/workspace/simple.dart
@@ -9,7 +9,6 @@
import 'package:analyzer/src/source/package_map_resolver.dart';
import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/workspace/workspace.dart';
-import 'package:package_config/packages.dart';
/// An abstract class for simple workspaces which do not feature any build
/// artifacts or generated files.
@@ -20,28 +19,14 @@
/// The [ResourceProvider] by which paths are converted into [Resource]s.
final ResourceProvider provider;
+ @override
+ Map<String, List<Folder>> packageMap;
+
/// The absolute workspace root path.
@override
final String root;
- final ContextBuilder _builder;
-
- Map<String, List<Folder>> _packageMap;
-
- Packages _packages;
-
- SimpleWorkspace(this.provider, this.root, this._builder);
-
- @override
- Map<String, List<Folder>> get packageMap {
- _packageMap ??= _builder.convertPackagesToMap(packages);
- return _packageMap;
- }
-
- Packages get packages {
- _packages ??= _builder.createPackageMap(root);
- return _packages;
- }
+ SimpleWorkspace(this.provider, this.packageMap, this.root);
@override
UriResolver get packageUriResolver =>
diff --git a/pkg/analyzer/lib/src/workspace/workspace.dart b/pkg/analyzer/lib/src/workspace/workspace.dart
index 9b70903..1d6de14 100644
--- a/pkg/analyzer/lib/src/workspace/workspace.dart
+++ b/pkg/analyzer/lib/src/workspace/workspace.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/file_system/file_system.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/package_bundle_reader.dart';
@@ -14,22 +13,11 @@
*/
abstract class Workspace {
/**
- * Return `true` if this workspace defines a single "project" and that
- * "project" depends upon flutter.
- */
- bool get hasFlutterDependency => packageMap?.containsKey('flutter') ?? false;
-
- /**
* Return true iff this [Workspace] is a [BazelWorkspace].
*/
bool get isBazel => false;
/**
- * Return a (possibly null) map of package sources.
- */
- Map<String, List<Folder>> get packageMap;
-
- /**
* The [UriResolver] that can resolve `package` URIs.
*/
UriResolver get packageUriResolver;
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 5d1965d..8cf3d18 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -13,7 +13,6 @@
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -442,57 +441,6 @@
_listener.assertNoErrors();
}
- test_visitBinaryExpression_bangEq() async {
- // String i;
- // var j;
- // i == j
- InterfaceType stringType = _typeProvider.stringType;
- SimpleIdentifier left = AstTestFactory.identifier3("i");
- left.staticType = stringType;
- BinaryExpression expression = AstTestFactory.binaryExpression(
- left, TokenType.BANG_EQ, AstTestFactory.identifier3("j"));
- _resolveNode(expression);
- var stringElement = stringType.element;
- expect(expression.staticElement, isNotNull);
- expect(
- expression.staticElement,
- stringElement.lookUpMethod(
- TokenType.EQ_EQ.lexeme, stringElement.library));
- _listener.assertNoErrors();
- }
-
- test_visitBinaryExpression_eq() async {
- // String i;
- // var j;
- // i == j
- InterfaceType stringType = _typeProvider.stringType;
- SimpleIdentifier left = AstTestFactory.identifier3("i");
- left.staticType = stringType;
- BinaryExpression expression = AstTestFactory.binaryExpression(
- left, TokenType.EQ_EQ, AstTestFactory.identifier3("j"));
- _resolveNode(expression);
- var stringElement = stringType.element;
- expect(
- expression.staticElement,
- stringElement.lookUpMethod(
- TokenType.EQ_EQ.lexeme, stringElement.library));
- _listener.assertNoErrors();
- }
-
- test_visitBinaryExpression_plus() async {
- // num i;
- // var j;
- // i + j
- InterfaceType numType = _typeProvider.numType;
- SimpleIdentifier left = AstTestFactory.identifier3("i");
- left.staticType = numType;
- BinaryExpression expression = AstTestFactory.binaryExpression(
- left, TokenType.PLUS, AstTestFactory.identifier3("j"));
- _resolveNode(expression);
- expect(expression.staticElement, numType.getMethod('+'));
- _listener.assertNoErrors();
- }
-
test_visitBreakStatement_withLabel() async {
// loop: while (true) {
// break loop;
@@ -799,45 +747,6 @@
_listener.assertNoErrors();
}
- test_visitPostfixExpression() async {
- InterfaceType numType = _typeProvider.numType;
- SimpleIdentifier operand = AstTestFactory.identifier3("i");
- operand.staticType = numType;
- PostfixExpression expression =
- AstTestFactory.postfixExpression(operand, TokenType.PLUS_PLUS);
- _resolveNode(expression);
- expect(expression.staticElement, numType.getMethod('+'));
- _listener.assertNoErrors();
- }
-
- @failingTest
- test_visitPostfixExpression_bang() async {
- InterfaceType numType = _typeProvider.numType;
- SimpleIdentifier operand = AstTestFactory.identifier3("i");
- operand.staticType = numType;
- PostfixExpression expression =
- AstTestFactory.postfixExpression(operand, TokenType.BANG);
- // TODO(danrubel): fails with Unsupported operation
- _resolveNode(expression);
- _listener.assertErrorsWithCodes([StaticTypeWarningCode.UNDEFINED_OPERATOR]);
- }
-
- @failingTest
- test_visitPostfixExpression_bang_NNBD() async {
- // TODO(danrubel): enable NNBD
- InterfaceType numType = _typeProvider.numType;
- SimpleIdentifier operand = AstTestFactory.identifier3("i");
- operand.staticType = numType;
- PostfixExpression expression =
- AstTestFactory.postfixExpression(operand, TokenType.BANG);
- _resolveNode(expression);
- // TODO(danrubel): fails with Unsupported operation
- expect(expression.staticElement, numType.getMethod('!'));
- _listener.assertNoErrors();
- // TODO(scheglov) This is wrong: `expr!` should not be resolved to `num.!`.
- fail('Expectations are wrong.');
- }
-
test_visitPrefixedIdentifier_dynamic() async {
DartType dynamicType = _typeProvider.dynamicType;
SimpleIdentifier target = AstTestFactory.identifier3("a");
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 14efa23..d1b571d 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -4286,7 +4286,11 @@
}
void test_parseTopLevelVariable_late() {
- var unit = parseCompilationUnit('late a;', featureSet: nonNullable);
+ var unit = parseCompilationUnit('late a;',
+ featureSet: nonNullable,
+ errors: [
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 5, 1)
+ ]);
var declaration = unit.declarations[0] as TopLevelVariableDeclaration;
var declarationList = declaration.variables;
expect(declarationList.keyword, isNull);
@@ -4304,7 +4308,11 @@
}
void test_parseTopLevelVariable_late_init() {
- var unit = parseCompilationUnit('late a = 0;', featureSet: nonNullable);
+ var unit = parseCompilationUnit('late a = 0;',
+ featureSet: nonNullable,
+ errors: [
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 5, 1)
+ ]);
var declaration = unit.declarations[0] as TopLevelVariableDeclaration;
var declarationList = declaration.variables;
expect(declarationList.keyword, isNull);
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 6273223..90ae072 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -448,110 +448,6 @@
_listener.assertNoErrors();
}
- void test_visitBinaryExpression_equals() {
- // 2 == 3
- Expression node = AstTestFactory.binaryExpression(
- _resolvedInteger(2), TokenType.EQ_EQ, _resolvedInteger(3));
- expect(_analyze(node), same(_typeProvider.boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_ifNull() {
- // 1 ?? 1.5
- Expression node = AstTestFactory.binaryExpression(
- _resolvedInteger(1), TokenType.QUESTION_QUESTION, _resolvedDouble(1.5));
- expect(_analyze(node), _typeProvider.numType);
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_logicalAnd() {
- // false && true
- Expression node = AstTestFactory.binaryExpression(
- AstTestFactory.booleanLiteral(false),
- TokenType.AMPERSAND_AMPERSAND,
- AstTestFactory.booleanLiteral(true));
- expect(_analyze(node), same(_typeProvider.boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_logicalOr() {
- // false || true
- Expression node = AstTestFactory.binaryExpression(
- AstTestFactory.booleanLiteral(false),
- TokenType.BAR_BAR,
- AstTestFactory.booleanLiteral(true));
- expect(_analyze(node), same(_typeProvider.boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_notEquals() {
- // 2 != 3
- Expression node = AstTestFactory.binaryExpression(
- _resolvedInteger(2), TokenType.BANG_EQ, _resolvedInteger(3));
- expect(_analyze(node), same(_typeProvider.boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_plusID() {
- // 1 + 2.0
- BinaryExpression node = AstTestFactory.binaryExpression(
- _resolvedInteger(1), TokenType.PLUS, _resolvedDouble(2.0));
- node.staticElement = _typeProvider.numType.getMethod('+');
- expect(_analyze(node), same(_typeProvider.doubleType));
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_plusII() {
- // 1 + 2
- BinaryExpression node = AstTestFactory.binaryExpression(
- _resolvedInteger(1), TokenType.PLUS, _resolvedInteger(2));
- node.staticElement = _typeProvider.numType.getMethod('+');
- expect(_analyze(node), same(_typeProvider.intType));
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_slash() {
- // 2 / 2
- BinaryExpressionImpl node = AstTestFactory.binaryExpression(
- _resolvedInteger(2), TokenType.SLASH, _resolvedInteger(2));
- node.staticElement = _typeProvider.numType.getMethod('/');
- node.staticInvokeType = node.staticElement.type;
- expect(_analyze(node), _typeProvider.doubleType);
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_star_notSpecial() {
- // class A {
- // A operator *(double value);
- // }
- // (a as A) * 2.0
- ClassElementImpl classA = ElementFactory.classElement2("A");
- InterfaceType typeA = interfaceTypeStar(classA);
- MethodElement operator =
- ElementFactory.methodElement("*", typeA, [_typeProvider.doubleType]);
- classA.methods = <MethodElement>[operator];
-
- var asExpression = AstTestFactory.asExpression(
- AstTestFactory.identifier3("a"), AstTestFactory.typeName(classA));
- asExpression.staticType = typeA;
-
- BinaryExpressionImpl node = AstTestFactory.binaryExpression(
- asExpression, TokenType.PLUS, _resolvedDouble(2.0));
- node.staticElement = operator;
- node.staticInvokeType = node.staticElement.type;
- expect(_analyze(node), same(typeA));
- _listener.assertNoErrors();
- }
-
- void test_visitBinaryExpression_starID() {
- // 1 * 2.0
- BinaryExpression node = AstTestFactory.binaryExpression(
- _resolvedInteger(1), TokenType.PLUS, _resolvedDouble(2.0));
- node.staticElement = _typeProvider.numType.getMethod('*');
- expect(_analyze(node), same(_typeProvider.doubleType));
- _listener.assertNoErrors();
- }
-
void test_visitBooleanLiteral_false() {
// false
Expression node = AstTestFactory.booleanLiteral(false);
@@ -982,22 +878,6 @@
_listener.assertNoErrors();
}
- void test_visitPostfixExpression_minusMinus() {
- // 0--
- PostfixExpression node = AstTestFactory.postfixExpression(
- _resolvedInteger(0), TokenType.MINUS_MINUS);
- expect(_analyze(node), same(_typeProvider.intType));
- _listener.assertNoErrors();
- }
-
- void test_visitPostfixExpression_plusPlus() {
- // 0++
- PostfixExpression node = AstTestFactory.postfixExpression(
- _resolvedInteger(0), TokenType.PLUS_PLUS);
- expect(_analyze(node), same(_typeProvider.intType));
- _listener.assertNoErrors();
- }
-
void test_visitPrefixedIdentifier_getter() {
DartType boolType = _typeProvider.boolType;
PropertyAccessorElementImpl getter =
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index 78958c0..ff0feb7 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/src/command_line/arguments.dart';
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/context/context_root.dart';
+import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/context/source.dart';
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -24,8 +25,6 @@
import 'package:analyzer/src/workspace/pub.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:args/args.dart';
-import 'package:package_config/packages.dart';
-import 'package:package_config/src/packages_impl.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -230,32 +229,6 @@
// _expectEqualOptions(options, expected);
}
- void test_convertPackagesToMap_noPackages() {
- expect(builder.convertPackagesToMap(Packages.noPackages), isEmpty);
- }
-
- void test_convertPackagesToMap_null() {
- expect(builder.convertPackagesToMap(null), isEmpty);
- }
-
- void test_convertPackagesToMap_packages() {
- String fooName = 'foo';
- String fooPath = convertPath('/pkg/foo');
- Uri fooUri = resourceProvider.pathContext.toUri(fooPath);
- String barName = 'bar';
- String barPath = convertPath('/pkg/bar');
- Uri barUri = resourceProvider.pathContext.toUri(barPath);
-
- MapPackages packages = MapPackages({fooName: fooUri, barName: barUri});
- Map<String, List<Folder>> result = builder.convertPackagesToMap(packages);
- expect(result, isNotNull);
- expect(result, hasLength(2));
- expect(result[fooName], hasLength(1));
- expect(result[fooName][0].path, fooPath);
- expect(result[barName], hasLength(1));
- expect(result[barName][0].path, barPath);
- }
-
void test_createDefaultOptions_default() {
// Invert a subset of the options to ensure that the default options are
// being returned.
@@ -289,11 +262,13 @@
builderOptions.defaultPackagesDirectoryPath = packageDirPath;
Packages packages = builder.createPackageMap(projectPath);
- expect(packages, isNotNull);
- Map<String, Uri> map = packages.asMap();
- expect(map, hasLength(2));
- expect(map[fooName], convertedDirectoryUri(fooPath));
- expect(map[barName], convertedDirectoryUri(barPath));
+ _assertPackages(
+ packages,
+ {
+ 'foo': convertPath('/root/packages/foo/lib'),
+ 'bar': convertPath('/root/packages/bar/lib'),
+ },
+ );
}
void test_createPackageMap_fromPackageDirectory_inRoot() {
@@ -308,11 +283,13 @@
newFolder(barPath);
Packages packages = builder.createPackageMap(projectPath);
- expect(packages, isNotNull);
- Map<String, Uri> map = packages.asMap();
- expect(map, hasLength(2));
- expect(map[fooName], convertedDirectoryUri(fooPath));
- expect(map[barName], convertedDirectoryUri(barPath));
+ _assertPackages(
+ packages,
+ {
+ 'foo': convertPath('/root/project/packages/foo/lib'),
+ 'bar': convertPath('/root/project/packages/bar/lib'),
+ },
+ );
}
void test_createPackageMap_fromPackageFile_explicit() {
@@ -321,20 +298,20 @@
String projectPath = join(rootPath, 'project');
String packageFilePath = join(rootPath, 'child', '.packages');
newFolder(projectPath);
- Uri fooUri = convertedDirectoryUri('/pkg/foo');
- Uri barUri = convertedDirectoryUri('/pkg/bar');
newFile(packageFilePath, content: '''
-foo:$fooUri
-bar:$barUri
+foo:${toUriStr('/pkg/foo')}
+bar:${toUriStr('/pkg/bar')}
''');
builderOptions.defaultPackageFilePath = packageFilePath;
Packages packages = builder.createPackageMap(projectPath);
- expect(packages, isNotNull);
- Map<String, Uri> map = packages.asMap();
- expect(map, hasLength(2));
- expect(map['foo'], fooUri);
- expect(map['bar'], barUri);
+ _assertPackages(
+ packages,
+ {
+ 'foo': convertPath('/pkg/foo'),
+ 'bar': convertPath('/pkg/bar'),
+ },
+ );
}
void test_createPackageMap_fromPackageFile_inParentOfRoot() {
@@ -343,19 +320,19 @@
String projectPath = join(rootPath, 'project');
String packageFilePath = join(rootPath, '.packages');
newFolder(projectPath);
- Uri fooUri = convertedDirectoryUri('/pkg/foo');
- Uri barUri = convertedDirectoryUri('/pkg/bar');
newFile(packageFilePath, content: '''
-foo:$fooUri
-bar:$barUri
+foo:${toUriStr('/pkg/foo')}
+bar:${toUriStr('/pkg/bar')}
''');
Packages packages = builder.createPackageMap(projectPath);
- expect(packages, isNotNull);
- Map<String, Uri> map = packages.asMap();
- expect(map, hasLength(2));
- expect(map['foo'], fooUri);
- expect(map['bar'], barUri);
+ _assertPackages(
+ packages,
+ {
+ 'foo': convertPath('/pkg/foo'),
+ 'bar': convertPath('/pkg/bar'),
+ },
+ );
}
void test_createPackageMap_fromPackageFile_inRoot() {
@@ -364,32 +341,32 @@
String projectPath = join(rootPath, 'project');
String packageFilePath = join(projectPath, '.packages');
newFolder(projectPath);
- Uri fooUri = convertedDirectoryUri('/pkg/foo');
- Uri barUri = convertedDirectoryUri('/pkg/bar');
newFile(packageFilePath, content: '''
-foo:$fooUri
-bar:$barUri
+foo:${toUriStr('/pkg/foo')}
+bar:${toUriStr('/pkg/bar')}
''');
Packages packages = builder.createPackageMap(projectPath);
- expect(packages, isNotNull);
- Map<String, Uri> map = packages.asMap();
- expect(map, hasLength(2));
- expect(map['foo'], fooUri);
- expect(map['bar'], barUri);
+ _assertPackages(
+ packages,
+ {
+ 'foo': convertPath('/pkg/foo'),
+ 'bar': convertPath('/pkg/bar'),
+ },
+ );
}
void test_createPackageMap_none() {
String rootPath = convertPath('/root');
newFolder(rootPath);
Packages packages = builder.createPackageMap(rootPath);
- expect(packages, same(Packages.noPackages));
+ expect(packages.packages, isEmpty);
}
void test_createPackageMap_rootDoesNotExist() {
String rootPath = convertPath('/root');
Packages packages = builder.createPackageMap(rootPath);
- expect(packages, same(Packages.noPackages));
+ expect(packages.packages, isEmpty);
}
void test_createSourceFactory_bazelWorkspace_fileProvider() {
@@ -848,6 +825,16 @@
expect(result.path, filePath);
}
+ void _assertPackages(Packages packages, Map<String, String> nameToPath) {
+ expect(packages, isNotNull);
+ expect(packages.packages, hasLength(nameToPath.length));
+ for (var name in nameToPath.keys) {
+ var expectedPath = nameToPath[name];
+ var path = packages[name].libFolder.path;
+ expect(path, expectedPath, reason: 'package $name');
+ }
+ }
+
_defineMockLintRules() {
_mockLintRule = _MockLintRule('mock_lint_rule');
Registry.ruleRegistry.register(_mockLintRule);
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
new file mode 100644
index 0000000..083f98c
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -0,0 +1,220 @@
+// 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/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(BinaryExpressionResolutionTest);
+ defineReflectiveTests(BinaryExpressionResolutionWithNnbdTest);
+ });
+}
+
+@reflectiveTest
+class BinaryExpressionResolutionTest extends DriverResolutionTest {
+ test_bangEq() async {
+ await assertNoErrorsInCode(r'''
+f(int a, int b) {
+ a != b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a != b'),
+ element: numElement.getMethod('=='),
+ type: 'bool',
+ );
+ }
+
+ test_eqEq() async {
+ await assertNoErrorsInCode(r'''
+f(int a, int b) {
+ a == b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a == b'),
+ element: numElement.getMethod('=='),
+ type: 'bool',
+ );
+ }
+
+ test_ifNull() async {
+ await assertNoErrorsInCode(r'''
+f(int a, double b) {
+ a ?? b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a ?? b'),
+ element: null,
+ type: 'num',
+ );
+ }
+
+ test_logicalAnd() async {
+ await assertNoErrorsInCode(r'''
+f(bool a, bool b) {
+ a && b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a && b'),
+ element: boolElement.getMethod('&&'),
+ type: 'bool',
+ );
+ }
+
+ test_logicalOr() async {
+ await assertNoErrorsInCode(r'''
+f(bool a, bool b) {
+ a || b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a || b'),
+ element: boolElement.getMethod('||'),
+ type: 'bool',
+ );
+ }
+
+ test_plus_int_double() async {
+ await assertNoErrorsInCode(r'''
+f(int a, double b) {
+ a + b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a + b'),
+ element: numElement.getMethod('+'),
+ type: 'double',
+ );
+ }
+
+ test_plus_int_int() async {
+ await assertNoErrorsInCode(r'''
+f(int a, int b) {
+ a + b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a + b'),
+ element: numElement.getMethod('+'),
+ type: 'int',
+ );
+ }
+
+ test_receiverTypeParameter_bound_dynamic() async {
+ await assertNoErrorsInCode(r'''
+f<T extends dynamic>(T a) {
+ a + 0;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a + 0'),
+ element: null,
+ type: 'dynamic',
+ );
+ }
+
+ test_receiverTypeParameter_bound_num() async {
+ await assertNoErrorsInCode(r'''
+f<T extends num>(T a) {
+ a + 0;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a + 0'),
+ element: numElement.getMethod('+'),
+ type: 'num',
+ );
+ }
+
+ test_slash() async {
+ await assertNoErrorsInCode(r'''
+f(int a, int b) {
+ a / b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a / b'),
+ element: numElement.getMethod('/'),
+ type: 'double',
+ );
+ }
+
+ test_star_int_double() async {
+ await assertNoErrorsInCode(r'''
+f(int a, double b) {
+ a * b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a * b'),
+ element: numElement.getMethod('*'),
+ type: 'double',
+ );
+ }
+
+ test_star_int_int() async {
+ await assertNoErrorsInCode(r'''
+f(int a, int b) {
+ a * b;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('a * b'),
+ element: numElement.getMethod('*'),
+ type: 'int',
+ );
+ }
+}
+
+@reflectiveTest
+class BinaryExpressionResolutionWithNnbdTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..enabledExperiments = [EnableString.non_nullable]
+ ..implicitCasts = false;
+
+ @override
+ bool get typeToStringWithNullability => true;
+
+ test_ifNull_left_nullable() async {
+ await assertNoErrorsInCode(r'''
+T f<T>(T t) => t;
+
+int g() => f(null) ?? 0;
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('f(null)'),
+ element: findElement.topFunction('f'),
+ typeArgumentTypes: ['int?'],
+ invokeType: 'int? Function(int?)',
+ type: 'int?',
+ );
+
+ assertBinaryExpression(
+ findNode.binary('?? 0'),
+ element: null,
+ type: 'int',
+ );
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 3143261..0420fdf 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -224,10 +224,12 @@
''', [
error(StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, 57, 3),
]);
- _assertInvalidInvocation(
- 'a.foo(0)',
- findElement.method('foo'),
- expectedNameType: '(int) → void',
+ assertMethodInvocation2(
+ findNode.methodInvocation('a.foo(0)'),
+ element: findElement.method('foo'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function(int)',
+ type: 'void',
);
}
@@ -783,12 +785,15 @@
.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
71,
3),
+ error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS, 74, 3),
]);
- _assertInvalidInvocation(
- 'foo(0)',
- findElement.method('foo'),
- expectedNameType: '(int) → void',
+ assertMethodInvocation2(
+ findNode.methodInvocation('foo(0)'),
+ element: findElement.method('foo'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
);
}
@@ -969,7 +974,7 @@
foo<int>();
}
''', [
- error(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD, 26, 3),
+ error(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD, 29, 5),
]);
assertMethodInvocation(
findNode.methodInvocation('foo<int>()'),
@@ -987,13 +992,13 @@
foo<int>();
}
''', [
- error(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD, 55, 3),
+ error(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD, 58, 5),
]);
assertMethodInvocation(
findNode.methodInvocation('foo<int>()'),
findElement.topFunction('foo'),
- 'Map<num, dynamic> Function()',
- expectedTypeArguments: ['num', 'dynamic'],
+ 'Map<dynamic, dynamic> Function()',
+ expectedTypeArguments: ['dynamic', 'dynamic'],
);
assertTypeName(findNode.typeName('int>'), intElement, 'int');
}
@@ -1582,19 +1587,6 @@
assertType(foo, 'void Function(int)');
}
- test_noReceiver_parameter_call_nullAware() async {
- await assertNoErrorsInCode(r'''
-double Function(int) foo;
-
-main() {
- foo?.call(1);
-}
- ''');
-
- var invocation = findNode.methodInvocation('call(1)');
- assertTypeLegacy(invocation.target);
- }
-
test_noReceiver_method_superClass() async {
await assertNoErrorsInCode(r'''
class A {
@@ -1635,6 +1627,19 @@
);
}
+ test_noReceiver_parameter_call_nullAware() async {
+ await assertNoErrorsInCode(r'''
+double Function(int) foo;
+
+main() {
+ foo?.call(1);
+}
+ ''');
+
+ var invocation = findNode.methodInvocation('call(1)');
+ assertTypeLegacy(invocation.target);
+ }
+
test_noReceiver_topFunction() async {
await assertNoErrorsInCode(r'''
void foo(int _) {}
@@ -1768,7 +1773,8 @@
foo<int, double>();
}
''', [
- error(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD, 29, 3),
+ error(
+ StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD, 32, 13),
]);
var invocation = findNode.methodInvocation('foo<int, double>();');
assertTypeArgumentTypes(invocation, ['dynamic']);
diff --git a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
index 78ed3b2..1f63ff2 100644
--- a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -274,45 +274,6 @@
assertType(findNode.typeName('A {} // 2'), 'A');
}
- test_nonNullPromotion_typeParameter() async {
- await assertErrorsInCode(r'''
-class C<T> {
- void foo(T? t) {
- T temp = t!;
- }
- T bar(T? t) {
- return t!;
- }
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 38, 4),
- ]);
- }
-
- test_null_assertion_operator_changes_null_to_never() async {
- await assertErrorsInCode('''
-main() {
- Null x = null;
- x!;
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 16, 1),
- ]);
- assertType(findNode.postfix('x!'), 'Never');
- }
-
- test_null_assertion_operator_removes_nullability() async {
- await assertErrorsInCode('''
-main() {
- Object? x = null;
- x!;
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 19, 1),
- ]);
- assertType(findNode.postfix('x!'), 'Object');
- }
-
test_parameter_functionTyped() async {
await assertNoErrorsInCode('''
void f1(void p1()) {}
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
new file mode 100644
index 0000000..ea38101
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -0,0 +1,167 @@
+// 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/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(PostfixExpressionResolutionTest);
+ defineReflectiveTests(PostfixExpressionResolutionWithNnbdTest);
+ });
+}
+
+@reflectiveTest
+class PostfixExpressionResolutionTest extends DriverResolutionTest {
+ test_dec_localVariable() async {
+ await assertNoErrorsInCode(r'''
+f(int x) {
+ x--;
+}
+''');
+
+ assertPostfixExpression(
+ findNode.postfix('x--'),
+ element: numElement.getMethod('-'),
+ type: 'int',
+ );
+ }
+
+ test_inc_localVariable() async {
+ await assertNoErrorsInCode(r'''
+f(int x) {
+ x++;
+}
+''');
+
+ assertPostfixExpression(
+ findNode.postfix('x++'),
+ element: numElement.getMethod('+'),
+ type: 'int',
+ );
+ }
+
+ test_inc_property_differentTypes() async {
+ await assertNoErrorsInCode(r'''
+dynamic get x => 0;
+
+set x(Object _) {}
+
+f() {
+ x++;
+}
+''');
+
+ assertSimpleIdentifier(
+ findNode.simple('x++'),
+ element: findElement.topSet('x'),
+ type: 'Object',
+ );
+
+ assertPostfixExpression(
+ findNode.postfix('x++'),
+ element: null,
+ type: 'dynamic',
+ );
+ }
+}
+
+@reflectiveTest
+class PostfixExpressionResolutionWithNnbdTest
+ extends PostfixExpressionResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions =>
+ AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+
+ @override
+ bool get typeToStringWithNullability => true;
+
+ test_inc_localVariable_depromote() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ Object operator +(int _) => this;
+}
+
+f(Object x) {
+ if (x is A) {
+ x++;
+ x; // ref
+ }
+}
+''');
+
+ assertType(findNode.simple('x++;'), 'A');
+
+ assertPostfixExpression(
+ findNode.postfix('x++'),
+ element: findElement.method('+'),
+ type: 'A',
+ );
+
+ assertType(findNode.simple('x; // ref'), 'Object');
+ }
+
+ test_nullCheck() async {
+ await assertNoErrorsInCode(r'''
+f(int? x) {
+ x!;
+}
+''');
+
+ assertPostfixExpression(
+ findNode.postfix('x!'),
+ element: null,
+ type: 'int',
+ );
+ }
+
+ test_nullCheck_null() async {
+ await assertNoErrorsInCode('''
+main(Null x) {
+ x!;
+}
+''');
+
+ assertType(findNode.postfix('x!'), 'Never');
+ }
+
+ test_nullCheck_nullableContext() async {
+ await assertNoErrorsInCode(r'''
+T f<T>(T t) => t;
+
+int g() => f(null)!;
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('f(null)'),
+ element: findElement.topFunction('f'),
+ typeArgumentTypes: ['int?'],
+ invokeType: 'int? Function(int?)',
+ type: 'int?',
+ );
+
+ assertPostfixExpression(
+ findNode.postfix('f(null)!'),
+ element: null,
+ type: 'int',
+ );
+ }
+
+ test_nullCheck_typeParameter() async {
+ await assertNoErrorsInCode(r'''
+f<T>(T? x) {
+ x!;
+}
+''');
+
+ assertPostfixExpression(
+ findNode.postfix('x!'),
+ element: null,
+ type: 'T',
+ );
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index 92a29b2..ba65a7c 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -6,6 +6,7 @@
import 'assignment_test.dart' as assignment;
import 'ast_rewrite_test.dart' as ast_rewrite;
+import 'binary_expression_test.dart' as binary_expression;
import 'class_alias_test.dart' as class_alias;
import 'class_test.dart' as class_resolution;
import 'comment_test.dart' as comment;
@@ -39,6 +40,7 @@
import 'namespace_test.dart' as namespace;
import 'non_nullable_test.dart' as non_nullable;
import 'optional_const_test.dart' as optional_const;
+import 'postfix_expression_test.dart' as postfix_expression;
import 'prefix_expression_test.dart' as prefix_expression;
import 'prefixed_identifier_test.dart' as prefixed_identifier;
import 'property_access_test.dart' as property_access;
@@ -50,6 +52,7 @@
defineReflectiveSuite(() {
assignment.main();
ast_rewrite.main();
+ binary_expression.main();
class_alias.main();
class_resolution.main();
comment.main();
@@ -80,6 +83,7 @@
namespace.main();
non_nullable.main();
optional_const.main();
+ postfix_expression.main();
prefix_expression.main();
prefixed_identifier.main();
property_access.main();
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_reference_to_this_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_reference_to_this_test.dart
index 3054091..48fd70f 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_reference_to_this_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_reference_to_this_test.dart
@@ -144,7 +144,7 @@
test_instanceVariableInitializer_inDeclaration_late() async {
await assertNoErrorsInCode(r'''
class A {
- late f = this;
+ late var f = this;
}
''');
}
@@ -152,16 +152,16 @@
test_mixinVariableInitializer_inDeclaration_late() async {
await assertNoErrorsInCode(r'''
mixin A {
- late f = this;
+ late var f = this;
}
''');
}
test_variableInitializer_late() async {
await assertErrorsInCode('''
-late x = this;
+late var x = this;
''', [
- error(CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS, 9, 4),
+ error(CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS, 13, 4),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
index 7662cff..26be039 100644
--- a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
@@ -782,6 +782,7 @@
x.foo();
}
''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 54, 1),
error(StaticTypeWarningCode.UNDEFINED_METHOD, 56, 3),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
index 1632029..ecf7c3f 100644
--- a/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
@@ -705,22 +705,14 @@
AnalysisOptionsImpl get analysisOptions =>
AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
- test_bang_nonVoid() async {
- await assertNoErrorsInCode(r'''
-int? f() => 1;
-g() {
- f()!;
-}
-''');
- }
-
- test_bang_void() async {
+ test_nullCheck() async {
await assertErrorsInCode(r'''
-void f() => 1;
-g() {
- f()!;
+f(void x) {
+ x!;
}
-''', [ExpectedError(StaticWarningCode.USE_OF_VOID_RESULT, 23, 4)]);
+''', [ExpectedError(StaticWarningCode.USE_OF_VOID_RESULT, 14, 2)]);
+
+ assertType(findNode.postfix('x!'), 'void');
}
}
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index a4af38c..75b9376 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1903,7 +1903,7 @@
/*error:INVALID_OVERRIDE*/m(x) => x;
}
main() {
- int y = new D()./*error:WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD*/m<int>(42);
+ int y = new D().m/*error:WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD*/<int>(42);
print(y);
}
''');
diff --git a/pkg/analyzer/test/src/workspace/basic_test.dart b/pkg/analyzer/test/src/workspace/basic_test.dart
index 48f754f..f338eba 100644
--- a/pkg/analyzer/test/src/workspace/basic_test.dart
+++ b/pkg/analyzer/test/src/workspace/basic_test.dart
@@ -2,11 +2,8 @@
// 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/file_system/file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer/src/workspace/basic.dart';
-import 'package:package_config/packages.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -24,15 +21,9 @@
BasicWorkspace workspace;
setUp() {
- final contextBuilder = MockContextBuilder();
- final packages = MockPackages();
- final packageMap = <String, List<Folder>>{'project': []};
- contextBuilder.packagesMapMap[convertPath('/workspace')] = packages;
- contextBuilder.packagesToMapMap[packages] = packageMap;
-
newFolder('/workspace');
- workspace = BasicWorkspace.find(
- resourceProvider, convertPath('/workspace'), contextBuilder);
+ workspace =
+ BasicWorkspace.find(resourceProvider, {}, convertPath('/workspace'));
expect(workspace.isBazel, isFalse);
}
@@ -92,45 +83,23 @@
}
void test_find_directory() {
- BasicWorkspace workspace = BasicWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ BasicWorkspace workspace =
+ BasicWorkspace.find(resourceProvider, {}, convertPath('/workspace'));
expect(workspace.root, convertPath('/workspace'));
expect(workspace.isBazel, isFalse);
}
void test_find_fail_notAbsolute() {
expect(
- () => BasicWorkspace.find(resourceProvider, convertPath('not_absolute'),
- MockContextBuilder()),
+ () => BasicWorkspace.find(
+ resourceProvider, {}, convertPath('not_absolute')),
throwsA(TypeMatcher<ArgumentError>()));
}
void test_find_file() {
- BasicWorkspace workspace = BasicWorkspace.find(resourceProvider,
- convertPath('/workspace/project/lib/lib1.dart'), MockContextBuilder());
+ BasicWorkspace workspace = BasicWorkspace.find(
+ resourceProvider, {}, convertPath('/workspace/project/lib/lib1.dart'));
expect(workspace.root, convertPath('/workspace/project/lib'));
expect(workspace.isBazel, isFalse);
}
}
-
-class MockContextBuilder implements ContextBuilder {
- Map<String, Packages> packagesMapMap = <String, Packages>{};
- Map<Packages, Map<String, List<Folder>>> packagesToMapMap =
- <Packages, Map<String, List<Folder>>>{};
-
- @override
- Map<String, List<Folder>> convertPackagesToMap(Packages packages) =>
- packagesToMapMap[packages];
-
- @override
- Packages createPackageMap(String rootDirectoryPath) =>
- packagesMapMap[rootDirectoryPath];
-
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-class MockPackages implements Packages {
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/pkg/analyzer/test/src/workspace/package_build_test.dart b/pkg/analyzer/test/src/workspace/package_build_test.dart
index e71b398..630bf0c 100644
--- a/pkg/analyzer/test/src/workspace/package_build_test.dart
+++ b/pkg/analyzer/test/src/workspace/package_build_test.dart
@@ -3,12 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer/src/workspace/package_build.dart';
-import 'package:package_config/packages.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -23,28 +21,6 @@
});
}
-class MockContextBuilder implements ContextBuilder {
- Map<String, Packages> packagesMapMap = <String, Packages>{};
- Map<Packages, Map<String, List<Folder>>> packagesToMapMap =
- <Packages, Map<String, List<Folder>>>{};
-
- @override
- Map<String, List<Folder>> convertPackagesToMap(Packages packages) =>
- packagesToMapMap[packages];
-
- @override
- Packages createPackageMap(String rootDirectoryPath) =>
- packagesMapMap[rootDirectoryPath];
-
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-class MockPackages implements Packages {
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
class MockUriResolver implements UriResolver {
Map<Uri, File> uriToFile = {};
Map<String, Uri> pathToUri = {};
@@ -74,12 +50,14 @@
void setUp() {
newFolder('/workspace/.dart_tool/build/generated/project/lib');
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
- final MockContextBuilder contextBuilder = MockContextBuilder();
- final Packages packages = MockPackages();
- contextBuilder.packagesMapMap[convertPath('/workspace')] = packages;
- contextBuilder.packagesToMapMap[packages] = {'project': []};
+
workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), contextBuilder);
+ resourceProvider,
+ {
+ 'project': [getFolder('/workspace')]
+ },
+ convertPath('/workspace'),
+ );
resolver = PackageBuildFileUriResolver(workspace);
newFile('/workspace/test.dart');
newFile('/workspace/.dart_tool/build/generated/project/gen.dart');
@@ -221,12 +199,13 @@
newFile(path);
}
}
- final contextBuilder = MockContextBuilder();
- final packages = MockPackages();
- contextBuilder.packagesMapMap[convertPath(workspacePath)] = packages;
- contextBuilder.packagesToMapMap[packages] = {'project': []};
workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath(workspacePath), contextBuilder);
+ resourceProvider,
+ {
+ 'project': [getFolder('/workspace')]
+ },
+ convertPath(workspacePath),
+ );
packageUriResolver = MockUriResolver();
resolver = PackageBuildPackageUriResolver(workspace, packageUriResolver);
}
@@ -329,25 +308,15 @@
}
PackageBuildWorkspace _createPackageBuildWorkspace() {
- final contextBuilder = MockContextBuilder();
- final packagesForWorkspace = MockPackages();
- contextBuilder.packagesMapMap[convertPath('/workspace')] =
- packagesForWorkspace;
- contextBuilder.packagesToMapMap[packagesForWorkspace] = {
- 'project': <Folder>[getFolder('/workspace')]
- };
-
- final packagesForWorkspace2 = MockPackages();
- contextBuilder.packagesMapMap[convertPath('/workspace2')] =
- packagesForWorkspace2;
- contextBuilder.packagesToMapMap[packagesForWorkspace2] = {
- 'project2': <Folder>[]
- };
-
newFolder('/workspace/.dart_tool/build');
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), contextBuilder);
+ resourceProvider,
+ {
+ 'project': [getFolder('/workspace')]
+ },
+ convertPath('/workspace'),
+ );
packageUriResolver = MockUriResolver();
PackageBuildPackageUriResolver(workspace, packageUriResolver);
return workspace;
@@ -396,16 +365,25 @@
void test_find_fail_notAbsolute() {
expect(
- () => PackageBuildWorkspace.find(resourceProvider,
- convertPath('not_absolute'), MockContextBuilder()),
- throwsA(const TypeMatcher<ArgumentError>()));
+ () {
+ return PackageBuildWorkspace.find(
+ resourceProvider,
+ {},
+ convertPath('not_absolute'),
+ );
+ },
+ throwsArgumentError,
+ );
}
void test_find_hasDartToolAndPubspec() {
newFolder('/workspace/.dart_tool/build/generated/project/lib');
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace'),
+ );
expect(workspace.root, convertPath('/workspace'));
expect(workspace.projectPackageName, 'project');
}
@@ -417,9 +395,10 @@
'name: subproject'.codeUnits);
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider,
- convertPath('/workspace/opened/up/a/child/dir'),
- MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace/opened/up/a/child/dir'),
+ );
expect(workspace.root, convertPath('/workspace/opened/up/a/child/dir'));
expect(workspace.projectPackageName, 'subproject');
}
@@ -432,9 +411,10 @@
'not: yaml: here!!! 111'.codeUnits);
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider,
- convertPath('/workspace/opened/up/a/child/dir'),
- MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace/opened/up/a/child/dir'),
+ );
expect(workspace.root, convertPath('/workspace'));
expect(workspace.projectPackageName, 'project');
}
@@ -445,9 +425,10 @@
newFolder('/workspace/opened/up/a/child/dir/.dart_tool/build');
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider,
- convertPath('/workspace/opened/up/a/child/dir'),
- MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace/opened/up/a/child/dir'),
+ );
expect(workspace.root, convertPath('/workspace'));
expect(workspace.projectPackageName, 'project');
}
@@ -459,9 +440,10 @@
'name: subproject'.codeUnits);
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider,
- convertPath('/workspace/opened/up/a/child/dir'),
- MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace/opened/up/a/child/dir'),
+ );
expect(workspace.root, convertPath('/workspace'));
expect(workspace.projectPackageName, 'project');
}
@@ -471,14 +453,20 @@
newFolder('/workspace/.dart_tool');
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace'),
+ );
expect(workspace, isNull);
}
void test_find_hasDartToolNoPubspec() {
newFolder('/workspace/.dart_tool/build/generated/project/lib');
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace'),
+ );
expect(workspace, isNull);
}
@@ -487,7 +475,10 @@
newFolder('/workspace/.dart_tool/pub');
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace'),
+ );
expect(workspace, isNull);
}
@@ -496,14 +487,20 @@
newFileWithBytes(
'/workspace/pubspec.yaml', 'not: yaml: here! 1111'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace'),
+ );
expect(workspace, isNull);
}
void test_find_hasPubspecNoDartTool() {
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ resourceProvider,
+ {},
+ convertPath('/workspace'),
+ );
expect(workspace, isNull);
}
@@ -588,24 +585,17 @@
workspace.findFile(convertPath('/workspace/web/file.dart')), webFile);
}
- void test_supports_flutter() {
- newFolder('/workspace/.dart_tool/build');
- newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
- PackageBuildWorkspace workspace =
- _createWorkspace('/workspace', ['project', 'flutter']);
-
- expect(workspace.hasFlutterDependency, true);
- }
-
PackageBuildWorkspace _createWorkspace(
String root, List<String> packageNames) {
- final contextBuilder = MockContextBuilder();
- final packages = MockPackages();
- final packageMap = Map<String, List<Folder>>.fromIterable(packageNames,
- value: ((_) => []));
- contextBuilder.packagesMapMap[convertPath(root)] = packages;
- contextBuilder.packagesToMapMap[packages] = packageMap;
return PackageBuildWorkspace.find(
- resourceProvider, convertPath(root), contextBuilder);
+ resourceProvider,
+ Map.fromIterables(
+ packageNames,
+ packageNames.map(
+ (name) => [getFolder('/packages/$name/lib')],
+ ),
+ ),
+ convertPath(root),
+ );
}
}
diff --git a/pkg/analyzer/test/src/workspace/pub_test.dart b/pkg/analyzer/test/src/workspace/pub_test.dart
index ef2dcd0..c5d5c3c 100644
--- a/pkg/analyzer/test/src/workspace/pub_test.dart
+++ b/pkg/analyzer/test/src/workspace/pub_test.dart
@@ -2,11 +2,8 @@
// 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/file_system/file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer/src/workspace/pub.dart';
-import 'package:package_config/packages.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -19,42 +16,14 @@
});
}
-class MockContextBuilder implements ContextBuilder {
- Map<String, Packages> packagesMapMap = <String, Packages>{};
- Map<Packages, Map<String, List<Folder>>> packagesToMapMap =
- <Packages, Map<String, List<Folder>>>{};
-
- @override
- Map<String, List<Folder>> convertPackagesToMap(Packages packages) =>
- packagesToMapMap[packages];
-
- @override
- Packages createPackageMap(String rootDirectoryPath) =>
- packagesMapMap[rootDirectoryPath];
-
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-class MockPackages implements Packages {
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
@reflectiveTest
class PubWorkspacePackageTest with ResourceProviderMixin {
PubWorkspace workspace;
setUp() {
- final contextBuilder = MockContextBuilder();
- final packages = MockPackages();
- final packageMap = <String, List<Folder>>{'project': []};
- contextBuilder.packagesMapMap[convertPath('/workspace')] = packages;
- contextBuilder.packagesToMapMap[packages] = packageMap;
-
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
- workspace = PubWorkspace.find(
- resourceProvider, convertPath('/workspace'), contextBuilder);
+ workspace =
+ PubWorkspace.find(resourceProvider, {}, convertPath('/workspace'));
expect(workspace.isBazel, isFalse);
}
@@ -111,29 +80,29 @@
class PubWorkspaceTest with ResourceProviderMixin {
void test_find_directory() {
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
- PubWorkspace workspace = PubWorkspace.find(
- resourceProvider, convertPath('/workspace'), MockContextBuilder());
+ PubWorkspace workspace =
+ PubWorkspace.find(resourceProvider, {}, convertPath('/workspace'));
expect(workspace.isBazel, isFalse);
expect(workspace.root, convertPath('/workspace'));
}
void test_find_fail_notAbsolute() {
expect(
- () => PubWorkspace.find(resourceProvider, convertPath('not_absolute'),
- MockContextBuilder()),
+ () => PubWorkspace.find(
+ resourceProvider, {}, convertPath('not_absolute')),
throwsA(TypeMatcher<ArgumentError>()));
}
void test_find_file() {
newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
- PubWorkspace workspace = PubWorkspace.find(resourceProvider,
- convertPath('/workspace/lib/lib1.dart'), MockContextBuilder());
+ PubWorkspace workspace = PubWorkspace.find(
+ resourceProvider, {}, convertPath('/workspace/lib/lib1.dart'));
expect(workspace.root, convertPath('/workspace'));
}
void test_find_missingPubspec() {
- PubWorkspace workspace = PubWorkspace.find(resourceProvider,
- convertPath('/workspace/lib/lib1.dart'), MockContextBuilder());
+ PubWorkspace workspace = PubWorkspace.find(
+ resourceProvider, {}, convertPath('/workspace/lib/lib1.dart'));
expect(workspace, isNull);
}
}
diff --git a/pkg/analyzer_cli/analysis_options.yaml b/pkg/analyzer_cli/analysis_options.yaml
index 250a903..b4f4357 100644
--- a/pkg/analyzer_cli/analysis_options.yaml
+++ b/pkg/analyzer_cli/analysis_options.yaml
@@ -33,7 +33,7 @@
- null_closures
#- omit_local_variable_types # 273
- prefer_adjacent_string_concatenation
- #- prefer_collection_literals # 15
+ - prefer_collection_literals
- prefer_conditional_assignment
- prefer_contains
- prefer_equal_for_default_values
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index dbd70cc..54d6d76 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -43,7 +43,7 @@
final FileState libraryFile;
/// All files references by the analyzed library.
- final Set<String> files = Set<String>();
+ final Set<String> files = <String>{};
/// All [AnalysisErrorInfo]s in the analyzed library.
final List<ErrorsResult> errorsResults = [];
@@ -136,8 +136,8 @@
/// Fills [files].
void prepareSources(LibraryElement library) {
- var units = Set<CompilationUnitElement>();
- var libraries = Set<LibraryElement>();
+ var units = <CompilationUnitElement>{};
+ var libraries = <LibraryElement>{};
addLibrarySources(library, libraries, units);
}
diff --git a/pkg/analyzer_cli/lib/src/batch_mode.dart b/pkg/analyzer_cli/lib/src/batch_mode.dart
index 6f958ef..e0c8731 100644
--- a/pkg/analyzer_cli/lib/src/batch_mode.dart
+++ b/pkg/analyzer_cli/lib/src/batch_mode.dart
@@ -43,7 +43,7 @@
}
// Prepare arguments.
var lineArgs = line.split(RegExp('\\s+'));
- var args = List<String>();
+ var args = <String>[];
args.addAll(sharedArgs);
args.addAll(lineArgs);
args.remove('-b');
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index 65c6d32..1ef5c57 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -564,7 +564,7 @@
* Tracks paths to dependencies, really just a thin api around a Set<String>.
*/
class DependencyTracker {
- final _dependencies = Set<String>();
+ final _dependencies = <String>{};
/// The path to the file to create once tracking is done.
final String outputPath;
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 10b5e01..1c968c8 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -214,9 +214,9 @@
}
// These are used to do part file analysis across sources.
- Set<String> dartFiles = Set<String>();
- Set<FileState> libraryFiles = Set<FileState>();
- Set<FileState> danglingParts = Set<FileState>();
+ Set<String> dartFiles = <String>{};
+ Set<FileState> libraryFiles = <FileState>{};
+ Set<FileState> danglingParts = <FileState>{};
// Note: This references analysisDriver via closure, so it will change over
// time during the following analysis.
@@ -263,7 +263,7 @@
// Add all the files to be analyzed en masse to the context. Skip any
// files that were added earlier (whether explicitly or implicitly) to
// avoid causing those files to be unnecessarily re-read.
- Set<String> filesToAnalyze = Set<String>();
+ Set<String> filesToAnalyze = <String>{};
// Collect files for analysis.
// Note that these files will all be analyzed in the same context.
@@ -640,7 +640,7 @@
return null;
}
- Map<String, List<Folder>> folderMap = Map<String, List<Folder>>();
+ Map<String, List<Folder>> folderMap = <String, List<Folder>>{};
var pathContext = resourceProvider.pathContext;
packages.asMap().forEach((String packagePath, Uri uri) {
String path = fileUriToNormalizedPath(pathContext, uri);
@@ -775,7 +775,7 @@
'Package root directory ($packageRootPath) does not exist.');
}
var packages = packageRoot.listSync(followLinks: false);
- var result = Map<String, List<Folder>>();
+ var result = <String, List<Folder>>{};
for (var package in packages) {
var packageName = path.basename(package.path);
var realPath = package.resolveSymbolicLinksSync();
diff --git a/pkg/analyzer_cli/lib/src/error_formatter.dart b/pkg/analyzer_cli/lib/src/error_formatter.dart
index e20098e..daa9baf 100644
--- a/pkg/analyzer_cli/lib/src/error_formatter.dart
+++ b/pkg/analyzer_cli/lib/src/error_formatter.dart
@@ -196,7 +196,7 @@
void formatErrors(List<ErrorsResult> results) {
stats.unfilteredCount += results.length;
- List<AnalysisError> errors = List<AnalysisError>();
+ List<AnalysisError> errors = <AnalysisError>[];
Map<AnalysisError, ErrorsResult> errorToLine = {};
for (ErrorsResult result in results) {
for (AnalysisError error in result.errors) {
@@ -222,7 +222,7 @@
AnsiLogger ansi;
// This is a Set in order to de-dup CLI errors.
- final Set<CLIError> batchedErrors = Set();
+ final Set<CLIError> batchedErrors = {};
HumanErrorFormatter(
StringSink out, CommandLineOptions options, AnalysisStats stats,
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index d22f546..2f44d95 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -69,7 +69,7 @@
/// Try to find a appropriate directory to pass to "--dart-sdk" that will
/// allow summaries to be found.
String _findSdkDirForSummaries() {
- Set<String> triedDirectories = Set<String>();
+ Set<String> triedDirectories = <String>{};
bool isSuitable(String sdkDir) {
triedDirectories.add(sdkDir);
return File(path.join(sdkDir, 'lib', '_internal', 'strong.sum'))
diff --git a/pkg/analyzer_cli/tool/perf.dart b/pkg/analyzer_cli/tool/perf.dart
index 9437c2d..5e6e272 100644
--- a/pkg/analyzer_cli/tool/perf.dart
+++ b/pkg/analyzer_cli/tool/perf.dart
@@ -146,7 +146,7 @@
/// Load and scans all files we need to process: files reachable from the
/// entrypoint and all core libraries automatically included by the VM.
Set<Source> scanReachableFiles(Uri entryUri) {
- var files = Set<Source>();
+ var files = <Source>{};
var loadTimer = Stopwatch()..start();
collectSources(sources.forUri2(entryUri), files);
@@ -182,8 +182,8 @@
/// sources.
Future setup(Uri entryUri) async {
var provider = PhysicalResourceProvider.INSTANCE;
- var packageMap = ContextBuilder(provider, null, null)
- .convertPackagesToMap(await findPackages(entryUri));
+ var packageMap = ContextBuilder.convertPackagesToMap(
+ provider, await findPackages(entryUri));
sources = SourceFactory([
ResourceUriResolver(provider),
PackageMapUriResolver(provider, packageMap),
diff --git a/pkg/analyzer_plugin/analysis_options.yaml b/pkg/analyzer_plugin/analysis_options.yaml
index 53f1319..2000d43 100644
--- a/pkg/analyzer_plugin/analysis_options.yaml
+++ b/pkg/analyzer_plugin/analysis_options.yaml
@@ -12,7 +12,7 @@
- always_require_non_null_named_parameters
- annotate_overrides
- avoid_empty_else
- #- avoid_init_to_null # 19
+ - avoid_init_to_null
- avoid_null_checks_in_equality_operators
- avoid_relative_lib_imports
- avoid_return_types_on_setters
@@ -28,11 +28,11 @@
- null_closures
#- omit_local_variable_types # 1759
- prefer_adjacent_string_concatenation
- #- prefer_collection_literals # 9
+ - prefer_collection_literals
- prefer_conditional_assignment
- prefer_contains
- prefer_equal_for_default_values
- #- prefer_final_fields # 5
+ - prefer_final_fields
- prefer_for_elements_to_map_fromIterable
- prefer_generic_function_type_aliases
#- prefer_if_null_operators # 12
diff --git a/pkg/analyzer_plugin/lib/plugin/plugin.dart b/pkg/analyzer_plugin/lib/plugin/plugin.dart
index 556a34c..00529de 100644
--- a/pkg/analyzer_plugin/lib/plugin/plugin.dart
+++ b/pkg/analyzer_plugin/lib/plugin/plugin.dart
@@ -635,7 +635,7 @@
Future<Response> _getResponse(Request request, int requestTime) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
- ResponseResult result = null;
+ ResponseResult result;
switch (request.method) {
case ANALYSIS_REQUEST_GET_NAVIGATION:
var params = AnalysisGetNavigationParams.fromRequest(request);
diff --git a/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart b/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
index f727885..afeb695 100644
--- a/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
+++ b/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
@@ -89,7 +89,7 @@
/**
* The port used to send notifications and responses to the server.
*/
- SendPort _sendPort;
+ final SendPort _sendPort;
/**
* The port used to receive requests from the server.
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
index a185399..d4571c5 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
@@ -18,7 +18,7 @@
* The end-of-line marker used in the file being edited, or `null` if the
* default marker should be used.
*/
- String eol = null;
+ String eol;
/**
* A table mapping group ids to the associated linked edit groups.
@@ -174,7 +174,7 @@
* The end-of-line marker used in the file being edited, or `null` if the
* default marker should be used.
*/
- String _eol = null;
+ String _eol;
/**
* The buffer in which the content of the edit is being composed.
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 87e0a2b..26e57b4 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -94,7 +94,7 @@
* An [EditBuilder] used to build edits in Dart files.
*/
class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
- List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];
+ final List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];
/**
* Whether [_enclosingClass] and [_enclosingExecutable] have been initialized.
@@ -521,16 +521,8 @@
writeln();
write(prefix2);
selectAll(() {
- write('super.');
- write(memberName);
- write('(');
- for (int i = 0; i < parameters.length; i++) {
- if (i > 0) {
- write(', ');
- }
- write(parameters[i].name);
- }
- write(');');
+ write('super');
+ _writeSuperMemberInvocation(element, memberName, parameters);
});
writeln();
} else {
@@ -542,16 +534,8 @@
write(prefix2);
if (invokeSuper) {
selectAll(() {
- write('return super.');
- write(memberName);
- write('(');
- for (int i = 0; i < parameters.length; i++) {
- if (i > 0) {
- write(', ');
- }
- write(parameters[i].name);
- }
- write(');');
+ write('return super');
+ _writeSuperMemberInvocation(element, memberName, parameters);
});
} else {
selectAll(() {
@@ -654,7 +638,7 @@
void writeParametersMatchingArguments(ArgumentList argumentList) {
// TODO(brianwilkerson) Handle the case when there are required parameters
// after named parameters.
- Set<String> usedNames = Set<String>();
+ Set<String> usedNames = <String>{};
List<Expression> arguments = argumentList.arguments;
bool hasNamedParameters = false;
for (int i = 0; i < arguments.length; i++) {
@@ -728,7 +712,7 @@
addLinkedEdit(groupName, (LinkedEditBuilder builder) {
wroteType = _writeType(type, methodBeingCopied: methodBeingCopied);
if (wroteType && addSupertypeProposals) {
- _addSuperTypeProposals(builder, type, Set<DartType>());
+ _addSuperTypeProposals(builder, type, <DartType>{});
}
});
} else {
@@ -869,7 +853,7 @@
}
String _getBaseNameFromUnwrappedExpression(Expression expression) {
- String name = null;
+ String name;
// analyze expressions
if (expression is SimpleIdentifier) {
return expression.name;
@@ -963,7 +947,7 @@
*/
List<String> _getVariableNameSuggestionsForExpression(DartType expectedType,
Expression assignedExpression, Set<String> excluded) {
- Set<String> res = Set();
+ Set<String> res = {};
// use expression
if (assignedExpression != null) {
String nameFromExpression =
@@ -1076,6 +1060,21 @@
}
}
+ void _writeSuperMemberInvocation(ExecutableElement element, String memberName,
+ List<ParameterElement> parameters) {
+ final isOperator = element.isOperator;
+ write(isOperator ? ' ' : '.');
+ write(memberName);
+ write(isOperator ? ' ' : '(');
+ for (int i = 0; i < parameters.length; i++) {
+ if (i > 0) {
+ write(', ');
+ }
+ write(parameters[i].name);
+ }
+ write(isOperator ? ';' : ');');
+ }
+
/**
* Write the code to reference [type] in this compilation unit.
*
@@ -1306,7 +1305,7 @@
return ImportLibraryElementResultImpl(null);
}
- String importLibraryWithRelativeUri(String uriText, [String prefix = null]) {
+ String importLibraryWithRelativeUri(String uriText, [String prefix]) {
return _importLibraryWithRelativeUri(uriText, prefix).uriText;
}
@@ -1566,7 +1565,7 @@
* [uriText].
*/
_LibraryToImport _importLibraryWithRelativeUri(String uriText,
- [String prefix = null]) {
+ [String prefix]) {
var import = librariesToRelativelyImport[uriText];
if (import == null) {
import = _LibraryToImport(uriText, prefix);
@@ -1624,7 +1623,7 @@
@override
void addSuperTypesAsSuggestions(DartType type) {
- _addSuperTypesAsSuggestions(type, Set<DartType>());
+ _addSuperTypesAsSuggestions(type, <DartType>{});
}
/**
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/element_suggestion_builder.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/element_suggestion_builder.dart
index 87daf76..5878519 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/element_suggestion_builder.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/element_suggestion_builder.dart
@@ -23,7 +23,7 @@
/**
* A set of existing completions used to prevent duplicate suggestions.
*/
- final Set<String> _completions = Set<String>();
+ final Set<String> _completions = <String>{};
/**
* A map of element names to suggestions for synthetic getters and setters.
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
index 6baa843..86403e9 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
@@ -132,7 +132,7 @@
* The type that is required by the context in which the completion was
* activated, or `null` if there is no such type, or it cannot be determined.
*/
- DartType _requiredType = null;
+ DartType _requiredType;
/**
* Determine the suggestions that should be made based upon the given
diff --git a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
index e92ac3b..5bdf50e 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
@@ -249,7 +249,7 @@
} else if (param is NormalFormalParameter) {
normalParam = param;
}
- TypeAnnotation type = null;
+ TypeAnnotation type;
if (normalParam is FieldFormalParameter) {
type = normalParam.type;
} else if (normalParam is FunctionTypedFormalParameter) {
diff --git a/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart b/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
index 088ab48..57abe69 100644
--- a/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
+++ b/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
@@ -353,12 +353,12 @@
* Note: the enumerated values stored in this map are intended to be bitwise
* compared.
*/
- Map<String, int> _completionTypesGenerated = HashMap<String, int>();
+ final Map<String, int> _completionTypesGenerated = HashMap<String, int>();
/**
* Map from completion identifier to completion suggestion
*/
- Map<String, CompletionSuggestion> _suggestionMap =
+ final Map<String, CompletionSuggestion> _suggestionMap =
<String, CompletionSuggestion>{};
/**
diff --git a/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart b/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart
index 6e07db2..f3a4206 100644
--- a/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart
+++ b/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart
@@ -152,7 +152,7 @@
* [appliedTogetherMessage].
*/
const FixKind(this.name, this.priority, this.message,
- {this.appliedTogetherMessage = null});
+ {this.appliedTogetherMessage});
@override
int get hashCode => name.hashCode;
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 59ee846..72ea138 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -5,7 +5,7 @@
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_plugin
environment:
- sdk: '>=2.0.0 <3.0.0'
+ sdk: '>=2.3.0 <3.0.0'
dependencies:
analyzer: '>=0.35.3 <0.39.0'
diff --git a/pkg/analyzer_plugin/test/integration/support/integration_tests.dart b/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
index 4cf9c48..a77238c 100644
--- a/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
+++ b/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
@@ -421,7 +421,7 @@
/**
* Server process object, or null if server hasn't been started yet.
*/
- Process _process = null;
+ Process _process;
/**
* Commands that have been sent to the server but not yet acknowledged, and
@@ -457,7 +457,7 @@
/**
* Stopwatch that we use to generate timing information for debug output.
*/
- Stopwatch _time = Stopwatch();
+ final Stopwatch _time = Stopwatch();
/**
* The [currentElapseTime] at which the last communication was received from the server
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 1b7da81..880ac38 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -916,7 +916,7 @@
await builder.addFileEdit(path, (FileEditBuilder builder) {
builder.addInsertion(2, (EditBuilder builder) {
(builder as DartEditBuilder)
- .writeParameterMatchingArgument(argument, 0, Set<String>());
+ .writeParameterMatchingArgument(argument, 0, <String>{});
});
});
SourceEdit edit = getEdit(builder);
diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
index d9f7b95..cf6fd01 100644
--- a/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
@@ -911,7 +911,7 @@
void assertTarget(
String entityText,
String nodeText, {
- int argIndex = null,
+ int argIndex,
String droppedToken,
bool isFunctionalArgument = false,
String expectedExecutable,
diff --git a/pkg/analyzer_plugin/test/support/abstract_context.dart b/pkg/analyzer_plugin/test/support/abstract_context.dart
index 0bee02c..eee4c1f 100644
--- a/pkg/analyzer_plugin/test/support/abstract_context.dart
+++ b/pkg/analyzer_plugin/test/support/abstract_context.dart
@@ -22,7 +22,7 @@
* Finds an [Element] with the given [name].
*/
Element findChildElement(Element root, String name, [ElementKind kind]) {
- Element result = null;
+ Element result;
root.accept(_ElementVisitorFunctionWrapper((Element element) {
if (element.name != name) {
return;
diff --git a/pkg/analyzer_plugin/test/utilities/completion/completion_contributor_util.dart b/pkg/analyzer_plugin/test/utilities/completion/completion_contributor_util.dart
index 3ff5e0b..7f31ef9 100644
--- a/pkg/analyzer_plugin/test/utilities/completion/completion_contributor_util.dart
+++ b/pkg/analyzer_plugin/test/utilities/completion/completion_contributor_util.dart
@@ -68,7 +68,7 @@
expect(suggestion.hasNamedParameters, isNotNull);
}
- void assertNoSuggestions({CompletionSuggestionKind kind = null}) {
+ void assertNoSuggestions({CompletionSuggestionKind kind}) {
if (kind == null) {
if (suggestions.isNotEmpty) {
failedCompletion('Expected no suggestions', suggestions);
@@ -95,7 +95,7 @@
CompletionSuggestion assertSuggest(String completion,
{CompletionSuggestionKind csKind = CompletionSuggestionKind.INVOCATION,
int relevance = DART_RELEVANCE_DEFAULT,
- ElementKind elemKind = null,
+ ElementKind elemKind,
bool isDeprecated = false,
bool isPotential = false,
String elemFile,
@@ -456,9 +456,9 @@
}
CompletionSuggestion getSuggest(
- {String completion = null,
- CompletionSuggestionKind csKind = null,
- ElementKind elemKind = null}) {
+ {String completion,
+ CompletionSuggestionKind csKind,
+ ElementKind elemKind}) {
CompletionSuggestion cs;
if (suggestions != null) {
suggestions.forEach((CompletionSuggestion s) {
diff --git a/pkg/analyzer_plugin/tool/spec/from_html.dart b/pkg/analyzer_plugin/tool/spec/from_html.dart
index 3a51897..1299a78 100644
--- a/pkg/analyzer_plugin/tool/spec/from_html.dart
+++ b/pkg/analyzer_plugin/tool/spec/from_html.dart
@@ -86,8 +86,8 @@
Api api;
List<String> versions = <String>[];
List<Domain> domains = <Domain>[];
- Types types = null;
- Refactorings refactorings = null;
+ Types types;
+ Refactorings refactorings;
recurse(html, 'api', {
'domain': (dom.Element element) {
domains.add(domainFromHtml(element));
@@ -120,7 +120,7 @@
void checkAttributes(
dom.Element element, List<String> requiredAttributes, String context,
{List<String> optionalAttributes = const []}) {
- Set<String> attributesFound = Set<String>();
+ Set<String> attributesFound = <String>{};
element.attributes.forEach((name, value) {
if (!requiredAttributes.contains(name) &&
!optionalAttributes.contains(name)) {
diff --git a/pkg/analyzer_plugin/tool/spec/to_html.dart b/pkg/analyzer_plugin/tool/spec/to_html.dart
index a192908..d032e31 100644
--- a/pkg/analyzer_plugin/tool/spec/to_html.dart
+++ b/pkg/analyzer_plugin/tool/spec/to_html.dart
@@ -220,7 +220,7 @@
/**
* Set of types defined in the API.
*/
- Set<String> definedTypes = Set<String>();
+ Set<String> definedTypes = <String>{};
/**
* Mappings from HTML elements to API nodes.
@@ -418,7 +418,7 @@
* boldface.
*/
void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) {
- Set<String> fieldsToBold = Set<String>();
+ Set<String> fieldsToBold = <String>{};
if (typeForBolding != null) {
for (TypeObjectField field in typeForBolding.fields) {
fieldsToBold.add(field.name);
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index e97afa01..6412b51 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -339,9 +339,8 @@
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = new Selector(SelectorKind.CALL, constructor.memberName,
_elementMap.getCallStructure(node.arguments));
- AbstractValue mask = _memberData.typeOfSend(node);
handleConstructorInvoke(
- node, node.arguments, selector, mask, constructor, arguments);
+ node, node.arguments, selector, constructor, arguments);
_inferrer.analyze(constructor);
if (_inferrer.checkIfExposesThis(constructor)) {
@@ -356,9 +355,8 @@
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = new Selector(SelectorKind.CALL, constructor.memberName,
_elementMap.getCallStructure(node.arguments));
- AbstractValue mask = _memberData.typeOfSend(node);
handleConstructorInvoke(
- node, node.arguments, selector, mask, constructor, arguments);
+ node, node.arguments, selector, constructor, arguments);
_inferrer.analyze(constructor);
if (_inferrer.checkIfExposesThis(constructor)) {
@@ -851,10 +849,32 @@
return new ArgumentsTypes(positional, named);
}
+ AbstractValue _typeOfReceiver(ir.TreeNode node, ir.TreeNode receiver) {
+ KernelGlobalTypeInferenceElementData data = _memberData;
+ AbstractValue mask = data.typeOfReceiver(node);
+ if (mask != null) return mask;
+ // TODO(sigmund): ensure that this is only called once per node.
+ DartType staticType = _getStaticType(receiver);
+ // TODO(sigmund): this needs to be adjusted when we enable non-nullable
+ // types to handle legacy and nullable wrappers.
+ if (staticType is InterfaceType) {
+ ClassEntity cls = staticType.element;
+ if (receiver is ir.ThisExpression && !_closedWorld.isUsedAsMixin(cls)) {
+ mask = _closedWorld.abstractValueDomain.createNonNullSubclass(cls);
+ } else {
+ mask = _closedWorld.abstractValueDomain.createNullableSubtype(cls);
+ }
+ data.setReceiverTypeMask(node, mask);
+ return mask;
+ }
+ // TODO(sigmund): consider also extracting the bound of type parameters.
+ return null;
+ }
+
@override
TypeInformation visitMethodInvocation(ir.MethodInvocation node) {
Selector selector = _elementMap.getSelector(node);
- AbstractValue mask = _memberData.typeOfSend(node);
+ AbstractValue mask = _typeOfReceiver(node, node.receiver);
ir.TreeNode receiver = node.receiver;
if (receiver is ir.VariableGet &&
@@ -868,7 +888,7 @@
}
TypeInformation type =
- handleStaticInvoke(node, selector, mask, info.callMethod, arguments);
+ handleStaticInvoke(node, selector, info.callMethod, arguments);
FunctionType functionType =
_elementMap.elementEnvironment.getFunctionType(info.callMethod);
if (functionType.returnType.containsFreeTypeVariables) {
@@ -1029,8 +1049,8 @@
_closedWorld.commonElements.streamIteratorConstructor;
/// Synthesize a call to the [StreamIterator] constructor.
- iteratorType = handleStaticInvoke(node, null, null, constructor,
- new ArgumentsTypes([expressionType], null));
+ iteratorType = handleStaticInvoke(
+ node, null, constructor, new ArgumentsTypes([expressionType], null));
} else {
TypeInformation expressionType = visit(node.iterable);
Selector iteratorSelector = Selectors.iterator;
@@ -1119,9 +1139,8 @@
ConstructorEntity constructor = _elementMap.getConstructor(node.target);
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = _elementMap.getSelector(node);
- AbstractValue mask = _memberData.typeOfSend(node);
return handleConstructorInvoke(
- node, node.arguments, selector, mask, constructor, arguments);
+ node, node.arguments, selector, constructor, arguments);
}
/// Try to find the length given to a fixed array constructor call.
@@ -1177,11 +1196,10 @@
ir.Node node,
ir.Arguments arguments,
Selector selector,
- AbstractValue mask,
ConstructorEntity constructor,
ArgumentsTypes argumentsTypes) {
TypeInformation returnType =
- handleStaticInvoke(node, selector, mask, constructor, argumentsTypes);
+ handleStaticInvoke(node, selector, constructor, argumentsTypes);
if (_elementMap.commonElements.isUnnamedListConstructor(constructor)) {
// We have `new List(...)`.
if (arguments.positional.isEmpty && arguments.named.isEmpty) {
@@ -1228,17 +1246,16 @@
}
TypeInformation handleStaticInvoke(ir.Node node, Selector selector,
- AbstractValue mask, MemberEntity element, ArgumentsTypes arguments) {
- return _inferrer.registerCalledMember(node, selector, mask, _analyzedMember,
+ MemberEntity element, ArgumentsTypes arguments) {
+ return _inferrer.registerCalledMember(node, selector, _analyzedMember,
element, arguments, _sideEffectsBuilder, inLoop);
}
TypeInformation handleClosureCall(ir.Node node, Selector selector,
- AbstractValue mask, MemberEntity member, ArgumentsTypes arguments) {
+ MemberEntity member, ArgumentsTypes arguments) {
return _inferrer.registerCalledClosure(
node,
selector,
- mask,
_inferrer.typeOfMember(member),
_analyzedMember,
arguments,
@@ -1246,14 +1263,10 @@
inLoop: inLoop);
}
- TypeInformation handleForeignInvoke(
- ir.StaticInvocation node,
- FunctionEntity function,
- ArgumentsTypes arguments,
- Selector selector,
- AbstractValue mask) {
+ TypeInformation handleForeignInvoke(ir.StaticInvocation node,
+ FunctionEntity function, ArgumentsTypes arguments, Selector selector) {
String name = function.name;
- handleStaticInvoke(node, selector, mask, function, arguments);
+ handleStaticInvoke(node, selector, function, arguments);
if (name == Identifiers.JS) {
NativeBehavior nativeBehavior =
_elementMap.getNativeBehaviorForJsCall(node);
@@ -1282,16 +1295,15 @@
MemberEntity member = _elementMap.getMember(node.target);
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = _elementMap.getSelector(node);
- AbstractValue mask = _memberData.typeOfSend(node);
if (_closedWorld.commonElements.isForeign(member)) {
- return handleForeignInvoke(node, member, arguments, selector, mask);
+ return handleForeignInvoke(node, member, arguments, selector);
} else if (member.isConstructor) {
return handleConstructorInvoke(
- node, node.arguments, selector, mask, member, arguments);
+ node, node.arguments, selector, member, arguments);
} else {
assert(member.isFunction, "Unexpected static invocation target: $member");
TypeInformation type =
- handleStaticInvoke(node, selector, mask, member, arguments);
+ handleStaticInvoke(node, selector, member, arguments);
FunctionType functionType =
_elementMap.elementEnvironment.getFunctionType(member);
if (functionType.returnType.containsFreeTypeVariables) {
@@ -1311,16 +1323,14 @@
@override
TypeInformation visitStaticGet(ir.StaticGet node) {
- AbstractValue mask = _memberData.typeOfSend(node);
- assert(mask == null);
- return createStaticGetTypeInformation(node, node.target, mask: mask);
+ return createStaticGetTypeInformation(node, node.target);
}
- TypeInformation createStaticGetTypeInformation(ir.Node node, ir.Member target,
- {AbstractValue mask}) {
+ TypeInformation createStaticGetTypeInformation(
+ ir.Node node, ir.Member target) {
MemberEntity member = _elementMap.getMember(target);
return handleStaticInvoke(
- node, new Selector.getter(member.memberName), mask, member, null);
+ node, new Selector.getter(member.memberName), member, null);
}
@override
@@ -1330,17 +1340,16 @@
_state.markThisAsExposed();
}
MemberEntity member = _elementMap.getMember(node.target);
- AbstractValue mask = _memberData.typeOfSend(node);
- handleStaticInvoke(node, new Selector.setter(member.memberName), mask,
- member, new ArgumentsTypes([rhsType], null));
+ handleStaticInvoke(node, new Selector.setter(member.memberName), member,
+ new ArgumentsTypes([rhsType], null));
return rhsType;
}
- TypeInformation handlePropertyGet(
- ir.TreeNode node, TypeInformation receiverType, ir.Member interfaceTarget,
+ TypeInformation handlePropertyGet(ir.TreeNode node, ir.TreeNode receiver,
+ TypeInformation receiverType, ir.Member interfaceTarget,
{bool isThis}) {
Selector selector = _elementMap.getSelector(node);
- AbstractValue mask = _memberData.typeOfSend(node);
+ AbstractValue mask = _typeOfReceiver(node, receiver);
if (isThis) {
_checkIfExposesThis(
selector, _types.newTypedSelector(receiverType, mask));
@@ -1363,21 +1372,23 @@
@override
TypeInformation visitPropertyGet(ir.PropertyGet node) {
TypeInformation receiverType = visit(node.receiver);
- return handlePropertyGet(node, receiverType, node.interfaceTarget,
+ return handlePropertyGet(
+ node, node.receiver, receiverType, node.interfaceTarget,
isThis: node.receiver is ir.ThisExpression);
}
@override
TypeInformation visitDirectPropertyGet(ir.DirectPropertyGet node) {
TypeInformation receiverType = thisType;
- return handlePropertyGet(node, receiverType, node.target, isThis: true);
+ return handlePropertyGet(node, node.receiver, receiverType, node.target,
+ isThis: true);
}
@override
TypeInformation visitPropertySet(ir.PropertySet node) {
TypeInformation receiverType = visit(node.receiver);
Selector selector = _elementMap.getSelector(node);
- AbstractValue mask = _memberData.typeOfSend(node);
+ AbstractValue mask = _typeOfReceiver(node, node.receiver);
TypeInformation rhsType = visit(node.value);
if (node.value is ir.ThisExpression) {
@@ -1730,13 +1741,13 @@
return _types.nonNullEmpty();
}
- TypeInformation handleSuperNoSuchMethod(ir.Node node, Selector selector,
- AbstractValue mask, ArgumentsTypes arguments) {
+ TypeInformation handleSuperNoSuchMethod(
+ ir.Node node, Selector selector, ArgumentsTypes arguments) {
// Ensure we create a node, to make explicit the call to the
// `noSuchMethod` handler.
FunctionEntity noSuchMethod =
_elementMap.getSuperNoSuchMethod(_analyzedMember.enclosingClass);
- return handleStaticInvoke(node, selector, mask, noSuchMethod, arguments);
+ return handleStaticInvoke(node, selector, noSuchMethod, arguments);
}
@override
@@ -1748,10 +1759,8 @@
MemberEntity member =
_elementMap.getSuperMember(_analyzedMember, node.name);
assert(member != null, "No member found for super property get: $node");
- AbstractValue mask = _memberData.typeOfSend(node);
Selector selector = new Selector.getter(_elementMap.getName(node.name));
- TypeInformation type =
- handleStaticInvoke(node, selector, mask, member, null);
+ TypeInformation type = handleStaticInvoke(node, selector, member, null);
if (member.isGetter) {
FunctionType functionType =
_elementMap.elementEnvironment.getFunctionType(member);
@@ -1781,10 +1790,9 @@
MemberEntity member =
_elementMap.getSuperMember(_analyzedMember, node.name, setter: true);
assert(member != null, "No member found for super property set: $node");
- AbstractValue mask = _memberData.typeOfSend(node);
Selector selector = new Selector.setter(_elementMap.getName(node.name));
ArgumentsTypes arguments = new ArgumentsTypes([rhsType], null);
- handleStaticInvoke(node, selector, mask, member, arguments);
+ handleStaticInvoke(node, selector, member, arguments);
return rhsType;
}
@@ -1798,17 +1806,16 @@
_elementMap.getSuperMember(_analyzedMember, node.name);
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = _elementMap.getSelector(node);
- AbstractValue mask = _memberData.typeOfSend(node);
if (member == null) {
// TODO(johnniwinther): This shouldn't be necessary.
- return handleSuperNoSuchMethod(node, selector, mask, arguments);
+ return handleSuperNoSuchMethod(node, selector, arguments);
} else {
assert(member.isFunction, "Unexpected super invocation target: $member");
if (isIncompatibleInvoke(member, arguments)) {
- return handleSuperNoSuchMethod(node, selector, mask, arguments);
+ return handleSuperNoSuchMethod(node, selector, arguments);
} else {
TypeInformation type =
- handleStaticInvoke(node, selector, mask, member, arguments);
+ handleStaticInvoke(node, selector, member, arguments);
FunctionType functionType =
_elementMap.elementEnvironment.getFunctionType(member);
if (functionType.returnType.containsFreeTypeVariables) {
diff --git a/pkg/compiler/lib/src/inferrer/closure_tracer.dart b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
index 3dd6f3f..0a01c9b 100644
--- a/pkg/compiler/lib/src/inferrer/closure_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
@@ -7,7 +7,6 @@
import '../common/names.dart' show Identifiers, Names;
import '../elements/entities.dart';
import '../universe/selector.dart' show Selector;
-import 'abstract_value_domain.dart';
import 'debug.dart' as debug;
import 'inferrer_engine.dart';
import 'node_tracer.dart';
@@ -56,14 +55,13 @@
void _analyzeCall(CallSiteTypeInformation info) {
Selector selector = info.selector;
- AbstractValue mask = info.mask;
tracedElements.forEach((FunctionEntity functionElement) {
if (!selector.callStructure
.signatureApplies(functionElement.parameterStructure)) {
return;
}
inferrer.updateParameterInputs(
- info, functionElement, info.arguments, selector, mask,
+ info, functionElement, info.arguments, selector,
remove: false, addToQueue: false);
});
}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 729e9bc..a510d20 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -208,7 +208,7 @@
assert(validCallType(callType, node, selector));
switch (callType) {
case CallType.access:
- data.setTypeMask(node, mask);
+ data.setReceiverTypeMask(node, mask);
break;
case CallType.indirectAccess:
// indirect access is not diretly recorded in the result data.
@@ -675,7 +675,8 @@
if (info is StaticCallSiteTypeInformation) {
MemberEntity member = info.calledElement;
inferredDataBuilder.addFunctionCalledInLoop(member);
- } else if (info.mask != null &&
+ } else if (info is DynamicCallSiteTypeInformation &&
+ info.mask != null &&
abstractValueDomain.containsAll(info.mask).isDefinitelyFalse) {
// For instance methods, we only register a selector called in a
// loop if it is a typed selector, to avoid marking too many
@@ -728,7 +729,7 @@
/// inputs must be added or removed. If [init] is false, parameters are
/// added to the work queue.
void updateParameterInputs(TypeInformation caller, MemberEntity callee,
- ArgumentsTypes arguments, Selector selector, AbstractValue mask,
+ ArgumentsTypes arguments, Selector selector,
{bool remove, bool addToQueue: true}) {
if (callee.name == Identifiers.noSuchMethod_) return;
if (callee.isField) {
@@ -898,7 +899,6 @@
TypeInformation registerCalledMember(
Object node,
Selector selector,
- AbstractValue mask,
MemberEntity caller,
MemberEntity callee,
ArgumentsTypes arguments,
@@ -911,7 +911,6 @@
caller,
callee,
selector,
- mask,
arguments,
inLoop);
// If this class has a 'call' method then we have essentially created a
@@ -953,52 +952,31 @@
{bool inLoop,
bool isConditional}) {
if (selector.isClosureCall) {
- return registerCalledClosure(node, selector, mask, receiverType, caller,
- arguments, sideEffectsBuilder,
+ return registerCalledClosure(
+ node, selector, receiverType, caller, arguments, sideEffectsBuilder,
inLoop: inLoop);
}
if (closedWorld.includesClosureCall(selector, mask)) {
sideEffectsBuilder.setAllSideEffectsAndDependsOnSomething();
}
+
closedWorld.locateMembers(selector, mask).forEach((callee) {
_updateSideEffects(sideEffectsBuilder, selector, callee);
});
- CallSiteTypeInformation info;
-
- // We force using indirection for `==` because it is a very common dynamic
- // call site on many apps.
- // TODO(sigmund): it would be even better if we could automatically detect
- // when dynamic calls are growing too big and add the indirection at that
- // point.
- if (selector.name == '==') {
- info = new IndirectDynamicCallSiteTypeInformation(
- abstractValueDomain,
- types.currentMember,
- node,
- _typeOfSharedDynamicCall(selector, CallStructure.ONE_ARG),
- caller,
- selector,
- mask,
- receiverType,
- arguments,
- inLoop,
- isConditional);
- } else {
- info = new DynamicCallSiteTypeInformation(
- abstractValueDomain,
- types.currentMember,
- callType,
- node,
- caller,
- selector,
- mask,
- receiverType,
- arguments,
- inLoop,
- isConditional);
- }
+ CallSiteTypeInformation info = new DynamicCallSiteTypeInformation(
+ abstractValueDomain,
+ types.currentMember,
+ callType,
+ node,
+ caller,
+ selector,
+ mask,
+ receiverType,
+ arguments,
+ inLoop,
+ isConditional);
info.addToGraph(this);
types.allocatedCalls.add(info);
return info;
@@ -1033,7 +1011,6 @@
TypeInformation registerCalledClosure(
ir.Node node,
Selector selector,
- AbstractValue mask,
TypeInformation closure,
MemberEntity caller,
ArgumentsTypes arguments,
@@ -1046,7 +1023,6 @@
node,
caller,
selector,
- mask,
closure,
arguments,
inLoop);
@@ -1142,6 +1118,8 @@
/// and call sites, we may have a quadratic number of edges in the graph, so
/// we add a level of indirection to merge the information and keep the graph
/// smaller.
+ // TODO(sigmund): start using or delete indirection logic.
+ // ignore: unused_element
DynamicCallSiteTypeInformation _typeOfSharedDynamicCall(
Selector selector, CallStructure structure) {
DynamicCallSiteTypeInformation info = _sharedCalls[selector];
@@ -1324,8 +1302,7 @@
/// objects in a debugging data stream.
static const String tag = 'global-type-inference-element-data';
- // TODO(johnniwinther): Rename this together with [typeOfSend].
- Map<ir.TreeNode, AbstractValue> _sendMap;
+ Map<ir.TreeNode, AbstractValue> _receiverMap;
Map<ir.ForInStatement, AbstractValue> _iteratorMap;
Map<ir.ForInStatement, AbstractValue> _currentMap;
@@ -1333,8 +1310,8 @@
KernelGlobalTypeInferenceElementData();
- KernelGlobalTypeInferenceElementData.internal(
- this._sendMap, this._iteratorMap, this._currentMap, this._moveNextMap);
+ KernelGlobalTypeInferenceElementData.internal(this._receiverMap,
+ this._iteratorMap, this._currentMap, this._moveNextMap);
/// Deserializes a [GlobalTypeInferenceElementData] object from [source].
factory KernelGlobalTypeInferenceElementData.readFromDataSource(
@@ -1370,7 +1347,7 @@
sink.inMemberContext(context, () {
sink.begin(tag);
sink.writeTreeNodeMapInContext(
- _sendMap,
+ _receiverMap,
(AbstractValue value) =>
abstractValueDomain.writeAbstractValueToDataSink(sink, value),
allowNull: true);
@@ -1395,10 +1372,10 @@
@override
GlobalTypeInferenceElementData compress() {
- if (_sendMap != null) {
- _sendMap.removeWhere(_mapsToNull);
- if (_sendMap.isEmpty) {
- _sendMap = null;
+ if (_receiverMap != null) {
+ _receiverMap.removeWhere(_mapsToNull);
+ if (_receiverMap.isEmpty) {
+ _receiverMap = null;
}
}
if (_iteratorMap != null) {
@@ -1419,7 +1396,7 @@
_moveNextMap = null;
}
}
- if (_sendMap == null &&
+ if (_receiverMap == null &&
_iteratorMap == null &&
_currentMap == null &&
_moveNextMap == null) {
@@ -1429,9 +1406,9 @@
}
@override
- AbstractValue typeOfSend(ir.TreeNode node) {
- if (_sendMap == null) return null;
- return _sendMap[node];
+ AbstractValue typeOfReceiver(ir.TreeNode node) {
+ if (_receiverMap == null) return null;
+ return _receiverMap[node];
}
void setCurrentTypeMask(ir.ForInStatement node, AbstractValue mask) {
@@ -1467,15 +1444,9 @@
return _iteratorMap[node];
}
- void setTypeMask(ir.TreeNode node, AbstractValue mask) {
- _sendMap ??= <ir.TreeNode, AbstractValue>{};
- _sendMap[node] = mask;
- }
-
- @override
- AbstractValue typeOfGetter(ir.TreeNode node) {
- if (_sendMap == null) return null;
- return _sendMap[node];
+ void setReceiverTypeMask(ir.TreeNode node, AbstractValue mask) {
+ _receiverMap ??= <ir.TreeNode, AbstractValue>{};
+ _receiverMap[node] = mask;
}
}
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 3091168..0e3fd2d 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -926,7 +926,6 @@
final Object _call;
final MemberEntity caller;
final Selector selector;
- final AbstractValue mask;
final ArgumentsTypes arguments;
final bool inLoop;
@@ -936,7 +935,6 @@
this._call,
this.caller,
this.selector,
- this.mask,
this.arguments,
this.inLoop)
: super.noInputs(abstractValueDomain.emptyType, context) {
@@ -965,10 +963,9 @@
MemberEntity enclosing,
this.calledElement,
Selector selector,
- AbstractValue mask,
ArgumentsTypes arguments,
bool inLoop)
- : super(abstractValueDomain, context, call, enclosing, selector, mask,
+ : super(abstractValueDomain, context, call, enclosing, selector,
arguments, inLoop);
MemberTypeInformation _getCalledTypeInfo(InferrerEngine inferrer) {
@@ -983,8 +980,7 @@
if (arguments != null) {
arguments.forEach((info) => info.addUser(this));
}
- inferrer.updateParameterInputs(
- this, calledElement, arguments, selector, mask,
+ inferrer.updateParameterInputs(this, calledElement, arguments, selector,
remove: false, addToQueue: false);
}
@@ -1052,6 +1048,7 @@
final DynamicCallSiteTypeInformation dynamicCall;
final bool isConditional;
final TypeInformation receiver;
+ final AbstractValue mask;
IndirectDynamicCallSiteTypeInformation(
AbstractValueDomain abstractValueDomain,
@@ -1060,12 +1057,12 @@
this.dynamicCall,
MemberEntity enclosing,
Selector selector,
- AbstractValue mask,
+ this.mask,
this.receiver,
ArgumentsTypes arguments,
bool inLoop,
this.isConditional)
- : super(abstractValueDomain, context, call, enclosing, selector, mask,
+ : super(abstractValueDomain, context, call, enclosing, selector,
arguments, inLoop);
@override
@@ -1143,6 +1140,7 @@
class DynamicCallSiteTypeInformation<T> extends CallSiteTypeInformation {
final CallType _callType;
final TypeInformation receiver;
+ final AbstractValue mask;
final bool isConditional;
bool _hasClosureCallTargets;
@@ -1156,12 +1154,12 @@
T call,
MemberEntity enclosing,
Selector selector,
- AbstractValue mask,
+ this.mask,
this.receiver,
ArgumentsTypes arguments,
bool inLoop,
this.isConditional)
- : super(abstractValueDomain, context, call, enclosing, selector, mask,
+ : super(abstractValueDomain, context, call, enclosing, selector,
arguments, inLoop) {
assert(validCallType(_callType, _call, selector));
}
@@ -1196,8 +1194,7 @@
inferrer.types.getInferredTypeOfMember(element);
_addCall(callee);
callee.addUser(this);
- inferrer.updateParameterInputs(
- this, element, arguments, selector, typeMask,
+ inferrer.updateParameterInputs(this, element, arguments, selector,
remove: false, addToQueue: false);
}
}
@@ -1360,8 +1357,7 @@
inferrer.types.getInferredTypeOfMember(element);
_addCall(callee);
callee.addUser(this);
- inferrer.updateParameterInputs(
- this, element, arguments, selector, typeMask,
+ inferrer.updateParameterInputs(this, element, arguments, selector,
remove: false, addToQueue: true);
});
@@ -1373,8 +1369,7 @@
inferrer.types.getInferredTypeOfMember(element);
_removeCall(callee);
callee.removeUser(this);
- inferrer.updateParameterInputs(
- this, element, arguments, selector, typeMask,
+ inferrer.updateParameterInputs(this, element, arguments, selector,
remove: true, addToQueue: true);
});
}
@@ -1448,8 +1443,7 @@
MemberTypeInformation callee =
inferrer.types.getInferredTypeOfMember(element);
callee.addCall(caller, _call);
- inferrer.updateParameterInputs(
- this, element, arguments, selector, mask,
+ inferrer.updateParameterInputs(this, element, arguments, selector,
remove: false, addToQueue: true);
}
}
@@ -1497,11 +1491,10 @@
Object call,
MemberEntity enclosing,
Selector selector,
- AbstractValue mask,
this.closure,
ArgumentsTypes arguments,
bool inLoop)
- : super(abstractValueDomain, context, call, enclosing, selector, mask,
+ : super(abstractValueDomain, context, call, enclosing, selector,
arguments, inLoop);
@override
diff --git a/pkg/compiler/lib/src/inferrer/types.dart b/pkg/compiler/lib/src/inferrer/types.dart
index 374f01a..5c5c4f1 100644
--- a/pkg/compiler/lib/src/inferrer/types.dart
+++ b/pkg/compiler/lib/src/inferrer/types.dart
@@ -52,13 +52,9 @@
/// The inferred return type when this result belongs to a function element.
AbstractValue get returnType;
- /// Returns the type of a send [node].
- // TODO(johnniwinther): Rename this.
- AbstractValue typeOfSend(ir.TreeNode node);
-
- /// Returns the type of the getter in a complex send-set [node], for example,
- /// the type of the `a.f` getter in `a.f += b`.
- AbstractValue typeOfGetter(ir.TreeNode node);
+ /// Returns the receiver type of a node that is a property get, set, or method
+ /// invocation.
+ AbstractValue typeOfReceiver(ir.TreeNode node);
/// Returns the type of the iterator in a [loop].
AbstractValue typeOfIterator(ir.TreeNode node);
@@ -88,8 +84,7 @@
GlobalTypeInferenceElementData compress();
// TODO(johnniwinther): Remove this. Maybe split by access/invoke.
- AbstractValue typeOfSend(ir.TreeNode node);
- AbstractValue typeOfGetter(ir.TreeNode node);
+ AbstractValue typeOfReceiver(ir.TreeNode node);
AbstractValue typeOfIterator(ir.TreeNode node);
@@ -443,9 +438,7 @@
}
@override
- AbstractValue typeOfSend(ir.Node node) => _data?.typeOfSend(node);
- @override
- AbstractValue typeOfGetter(ir.Node node) => _data?.typeOfGetter(node);
+ AbstractValue typeOfReceiver(ir.Node node) => _data?.typeOfReceiver(node);
@override
AbstractValue typeOfIterator(ir.Node node) => _data?.typeOfIterator(node);
@override
@@ -524,10 +517,7 @@
AbstractValue typeOfIterator(ir.Node node) => null;
@override
- AbstractValue typeOfGetter(ir.Node node) => null;
-
- @override
- AbstractValue typeOfSend(ir.Node node) => null;
+ AbstractValue typeOfReceiver(ir.Node node) => null;
@override
bool get isCalledOnce => false;
@@ -568,10 +558,7 @@
AbstractValue typeOfIterator(ir.Node node) => null;
@override
- AbstractValue typeOfGetter(ir.Node node) => null;
-
- @override
- AbstractValue typeOfSend(ir.Node node) => null;
+ AbstractValue typeOfReceiver(ir.Node node) => null;
@override
bool get isCalledOnce => false;
@@ -612,10 +599,7 @@
AbstractValue typeOfIterator(ir.Node node) => null;
@override
- AbstractValue typeOfGetter(ir.Node node) => null;
-
- @override
- AbstractValue typeOfSend(ir.Node node) => null;
+ AbstractValue typeOfReceiver(ir.Node node) => null;
@override
bool get isCalledOnce => false;
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 9eab8f8..3e31aa5e 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -539,23 +539,23 @@
@override
AbstractValue receiverTypeOfInvocation(
ir.MethodInvocation node, AbstractValueDomain abstractValueDomain) {
- return _targetResults.typeOfSend(node);
+ return _targetResults.typeOfReceiver(node);
}
@override
AbstractValue receiverTypeOfGet(ir.PropertyGet node) {
- return _targetResults.typeOfSend(node);
+ return _targetResults.typeOfReceiver(node);
}
@override
AbstractValue receiverTypeOfDirectGet(ir.DirectPropertyGet node) {
- return _targetResults.typeOfSend(node);
+ return _targetResults.typeOfReceiver(node);
}
@override
AbstractValue receiverTypeOfSet(
ir.PropertySet node, AbstractValueDomain abstractValueDomain) {
- return _targetResults.typeOfSend(node);
+ return _targetResults.typeOfReceiver(node);
}
@override
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index a7e3505..2306954 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -76,10 +76,6 @@
/// This should only set `true` by our REPL compiler.
bool replCompile;
- /// Mapping from absolute file paths to bazel short path to substitute in
- /// source maps.
- final Map<String, String> bazelMapping;
-
final Map<String, String> summaryModules;
final List<ModuleFormat> moduleFormats;
@@ -103,7 +99,6 @@
this.emitMetadata = false,
this.enableAsserts = true,
this.replCompile = false,
- this.bazelMapping = const {},
this.summaryModules = const {},
this.moduleFormats = const [],
this.experiments = const {},
@@ -119,8 +114,6 @@
enableAsserts: args['enable-asserts'] as bool,
experiments: parseExperimentalArguments(
args['enable-experiment'] as List<String>),
- bazelMapping:
- _parseBazelMappings(args['bazel-mapping'] as List<String>),
summaryModules: _parseCustomSummaryModules(
args['summary'] as List<String>, moduleRoot, summaryExtension),
moduleFormats: parseModuleFormatOption(args),
@@ -151,12 +144,6 @@
..addOption('module-name',
help: 'The output module name, used in some JS module formats.\n'
'Defaults to the output file name (without .js).')
- // TODO(jmesserly): rename this, it has nothing to do with bazel.
- ..addMultiOption('bazel-mapping',
- help: '--bazel-mapping=gen/to/library.dart,to/library.dart\n'
- 'adjusts the path in source maps.',
- splitCommas: false,
- hide: hide)
..addOption('library-root',
help: '(deprecated) used to name libraries inside the module, '
'ignored with -k.',
@@ -235,17 +222,6 @@
return pathToModule;
}
-Map<String, String> _parseBazelMappings(List<String> argument) {
- var mappings = <String, String>{};
- for (var mapping in argument) {
- var splitMapping = mapping.split(',');
- if (splitMapping.length >= 2) {
- mappings[p.absolute(splitMapping[0])] = splitMapping[1];
- }
- }
- return mappings;
-}
-
/// Taken from analyzer to implement `--ignore-unrecognized-flags`
List<String> filterUnknownArguments(List<String> args, ArgParser parser) {
if (!args.contains('--ignore-unrecognized-flags')) return args;
@@ -335,8 +311,7 @@
/// matching [multiRootScheme] are adjusted to be relative to
/// [multiRootOutputPath].
// TODO(jmesserly): find a new home for this.
-Map placeSourceMap(Map sourceMap, String sourceMapPath,
- Map<String, String> bazelMappings, String multiRootScheme,
+Map placeSourceMap(Map sourceMap, String sourceMapPath, String multiRootScheme,
{String multiRootOutputPath}) {
var map = Map.from(sourceMap);
// Convert to a local file path if it's not.
@@ -366,10 +341,6 @@
// Convert to a local file path if it's not.
sourcePath = sourcePathToUri(p.absolute(p.fromUri(uri))).path;
- // Allow bazel mappings to override.
- var match = bazelMappings != null ? bazelMappings[sourcePath] : null;
- if (match != null) return match;
-
// Fall back to a relative path against the source map itself.
sourcePath = p.url.relative(sourcePath, from: sourceMapDir);
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index f2666eb..8315891 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -407,7 +407,6 @@
inlineSourceMap: options.inlineSourceMap,
jsUrl: p.toUri(output).toString(),
mapUrl: p.toUri(output + '.map').toString(),
- bazelMapping: options.bazelMapping,
customScheme: multiRootScheme,
multiRootOutputPath: multiRootOutputPath);
@@ -507,7 +506,6 @@
inlineSourceMap: options.inlineSourceMap,
jsUrl: p.toUri(output).toString(),
mapUrl: p.toUri(output + '.map').toString(),
- bazelMapping: options.bazelMapping,
customScheme: multiRootScheme,
multiRootOutputPath: multiRootOutputPath);
@@ -543,7 +541,6 @@
bool inlineSourceMap = false,
String jsUrl,
String mapUrl,
- Map<String, String> bazelMapping,
String customScheme,
String multiRootOutputPath}) {
var opts = js_ast.JavaScriptPrintingOptions(
@@ -564,8 +561,7 @@
Map builtMap;
if (buildSourceMap && sourceMap != null) {
- builtMap = placeSourceMap(
- sourceMap.build(jsUrl), mapUrl, bazelMapping, customScheme,
+ builtMap = placeSourceMap(sourceMap.build(jsUrl), mapUrl, customScheme,
multiRootOutputPath: multiRootOutputPath);
var jsDir = p.dirname(p.fromUri(jsUrl));
var relative = p.relative(p.fromUri(mapUrl), from: jsDir);
diff --git a/pkg/dev_compiler/tool/nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/nnbd_sdk_error_golden.txt
index d9fd291..8b13789 100644
--- a/pkg/dev_compiler/tool/nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/nnbd_sdk_error_golden.txt
@@ -1,2 +1 @@
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/async/async.dart|5554|39|14|A value of type '_PendingEvents<T>?' can't be assigned to a variable of type '_PendingEvents<T>'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/async/async.dart|5390|14|8|A value of type 'Object?' can't be returned from function '_pendingEvents' because it has a return type of '_PendingEvents<T>?'.
+
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 210998e..132c992 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -3826,18 +3826,39 @@
forest.argumentsPositional(arguments).length)
.withLocation(uri, arguments.fileOffset, noLength);
}
- List<Object> named = forest.argumentsNamed(arguments);
+ List<NamedExpression> named = forest.argumentsNamed(arguments);
if (named.isNotEmpty) {
- Set<String> names =
+ Set<String> parameterNames =
new Set.from(function.namedParameters.map((a) => a.name));
for (NamedExpression argument in named) {
- if (!names.contains(argument.name)) {
+ if (!parameterNames.contains(argument.name)) {
return fasta.templateNoSuchNamedParameter
.withArguments(argument.name)
.withLocation(uri, argument.fileOffset, argument.name.length);
}
}
}
+ if (function.namedParameters.isNotEmpty) {
+ if (libraryBuilder.isNonNullableByDefault &&
+ libraryBuilder.loader.performNnbdChecks) {
+ Set<String> argumentNames = new Set.from(named.map((a) => a.name));
+ for (VariableDeclaration parameter in function.namedParameters) {
+ if (parameter.isRequired && !argumentNames.contains(parameter.name)) {
+ if (libraryBuilder.loader.nnbdStrongMode) {
+ return fasta.templateValueForRequiredParameterNotProvidedError
+ .withArguments(parameter.name)
+ .withLocation(uri, arguments.fileOffset, fasta.noLength);
+ } else {
+ addProblem(
+ fasta.templateValueForRequiredParameterNotProvidedWarning
+ .withArguments(parameter.name),
+ arguments.fileOffset,
+ fasta.noLength);
+ }
+ }
+ }
+ }
+ }
List<DartType> types = forest.argumentsTypeArguments(arguments);
if (typeParameters.length != types.length) {
@@ -3873,7 +3894,7 @@
forest.argumentsPositional(arguments).length)
.withLocation(uri, arguments.fileOffset, noLength);
}
- List<Object> named = forest.argumentsNamed(arguments);
+ List<NamedExpression> named = forest.argumentsNamed(arguments);
if (named.isNotEmpty) {
Set<String> names =
new Set.from(function.namedParameters.map((a) => a.name));
@@ -3885,6 +3906,27 @@
}
}
}
+ if (function.namedParameters.isNotEmpty) {
+ if (libraryBuilder.isNonNullableByDefault &&
+ libraryBuilder.loader.performNnbdChecks) {
+ Set<String> argumentNames = new Set.from(named.map((a) => a.name));
+ for (NamedType parameter in function.namedParameters) {
+ if (parameter.isRequired && !argumentNames.contains(parameter.name)) {
+ if (libraryBuilder.loader.nnbdStrongMode) {
+ return fasta.templateValueForRequiredParameterNotProvidedError
+ .withArguments(parameter.name)
+ .withLocation(uri, arguments.fileOffset, fasta.noLength);
+ } else {
+ addProblem(
+ fasta.templateValueForRequiredParameterNotProvidedWarning
+ .withArguments(parameter.name),
+ arguments.fileOffset,
+ fasta.noLength);
+ }
+ }
+ }
+ }
+ }
List<Object> types = forest.argumentsTypeArguments(arguments);
List<TypeParameter> typeParameters = function.typeParameters;
if (typeParameters.length != types.length && types.length != 0) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 52d77ba..1febb17 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -2491,6 +2491,10 @@
String uri = '${classBuilder.library.uri}';
if (uri == 'dart:js' &&
+ classBuilder.fileUri.pathSegments.last == 'js.dart' ||
+ // Remove 'js_dart2js.dart' once the file is renamed
+ // to 'js.dart' everywhere.
+ uri == 'dart:js' &&
classBuilder.fileUri.pathSegments.last == 'js_dart2js.dart' ||
uri == 'dart:_interceptors' &&
classBuilder.fileUri.pathSegments.last == 'js_number.dart') {
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 69b9af4..e88e95a 100644
--- a/pkg/front_end/lib/src/testing/id_testing_helper.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart
@@ -419,7 +419,7 @@
}
CfeCompiledData<T> compiledData = new CfeCompiledData<T>(
- compilerResult, testData.testFileUri, actualMaps, globalData);
+ compilerResult, testData.entryPoint, actualMaps, globalData);
return checkCode(config.name, testData.testFileUri, testData.code,
memberAnnotations, compiledData, dataComputer.dataValidator,
fatalErrors: fatalErrors, succinct: succinct, onFailure: onFailure);
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 770426b..694f491 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -595,6 +595,10 @@
UnterminatedToken/analyzerCode: Fail
UnterminatedToken/example: Fail
UntranslatableUri/part_wrapped_script: Fail # Importing file in the (now) part.
+ValueForRequiredParameterNotProvidedError/analyzerCode: Fail
+ValueForRequiredParameterNotProvidedError/example: Fail
+ValueForRequiredParameterNotProvidedWarning/analyzerCode: Fail
+ValueForRequiredParameterNotProvidedWarning/example: Fail
VarAsTypeName/part_wrapped_script1: Fail
VarAsTypeName/script1: Fail # Too many problems
WebLiteralCannotBeRepresentedExactly/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 1e72804..035c8e2 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -3761,3 +3761,10 @@
RequiredNamedParameterHasDefaultValueWarning:
template: "Required named parameter '#name' has a default value."
severity: WARNING
+
+ValueForRequiredParameterNotProvidedError:
+ template: "Required named parameter '#name' must be provided."
+
+ValueForRequiredParameterNotProvidedWarning:
+ template: "Missing required named parameter '#name'."
+ severity: WARNING
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776.dart b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart
new file mode 100644
index 0000000..127e1fe
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart
@@ -0,0 +1,10 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+ Function? f1 = foo;
+ f1!(42);
+
+ Function f2 = bar;
+ f2!<int>(42);
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.expect
new file mode 100644
index 0000000..7b185d5e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.expect
@@ -0,0 +1,130 @@
+beginCompilationUnit(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Object, ?)
+ handleIdentifier(foo, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(i)
+ handleType(int, null)
+ handleIdentifier(i, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginLiteralString("42")
+ endLiteralString(0, ;)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(;, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Object, ?)
+ handleIdentifier(bar, topLevelFunctionDeclaration)
+ beginTypeVariables(<)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ handleIdentifier(T, typeVariableDeclaration)
+ beginTypeVariable(T)
+ handleTypeVariablesDefined(T, 1)
+ handleNoType(T)
+ endTypeVariable(>, 0, null, null)
+ endTypeVariables(<, >)
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ beginFormalParameter(T, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(T, typeReference)
+ handleNoTypeArguments(t)
+ handleType(T, null)
+ handleIdentifier(t, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, t, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(main)
+ beginMetadataStar(main)
+ endMetadataStar(0)
+ beginTopLevelMember(main)
+ beginTopLevelMethod(;, null)
+ handleNoType(;)
+ handleIdentifier(main, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Function, ?)
+ beginVariablesDeclaration(f1, null, null)
+ handleIdentifier(f1, localVariableDeclaration)
+ beginInitializedIdentifier(f1)
+ beginVariableInitializer(=)
+ handleIdentifier(foo, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(foo, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f1)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f1, expression)
+ handleNoTypeArguments(!)
+ handleNoArguments(!)
+ handleSend(f1, !)
+ handleNonNullAssertExpression(!)
+ handleNoTypeArguments(()
+ beginArguments(()
+ handleLiteralInt(42)
+ endArguments(1, (, ))
+ handleSend((, ))
+ handleExpressionStatement(;)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(f2)
+ handleType(Function, null)
+ beginVariablesDeclaration(f2, null, null)
+ handleIdentifier(f2, localVariableDeclaration)
+ beginInitializedIdentifier(f2)
+ beginVariableInitializer(=)
+ handleIdentifier(bar, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(bar, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f2)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f2, expression)
+ handleNonNullAssertExpression(!)
+ beginTypeArguments(<)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(>)
+ handleType(int, null)
+ endTypeArguments(1, <, >)
+ beginArguments(()
+ handleLiteralInt(42)
+ endArguments(1, (, ))
+ handleSend(f2, ;)
+ handleExpressionStatement(;)
+ endBlockFunctionBody(4, {, })
+ endTopLevelMethod(main, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.intertwined.expect
new file mode 100644
index 0000000..3f3083a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.intertwined.expect
@@ -0,0 +1,285 @@
+parseUnit(Object)
+ skipErrorTokens(Object)
+ listener: beginCompilationUnit(Object)
+ syntheticPreviousToken(Object)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(, null, , Instance of 'SimpleNullableType', null, foo)
+ listener: beginTopLevelMethod(, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Object, ?)
+ ensureIdentifier(?, topLevelFunctionDeclaration)
+ listener: handleIdentifier(foo, topLevelFunctionDeclaration)
+ parseMethodTypeVar(foo)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo, foo, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(foo, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(i)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(i, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralString(=>)
+ parseSingleLiteralString(=>)
+ listener: beginLiteralString("42")
+ listener: endLiteralString(0, ;)
+ ensureSemicolon("42")
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(Object)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(;, null, ;, Instance of 'SimpleNullableType', null, bar)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Object, ?)
+ ensureIdentifier(?, topLevelFunctionDeclaration)
+ listener: handleIdentifier(bar, topLevelFunctionDeclaration)
+ parseMethodTypeVar(bar)
+ listener: beginTypeVariables(<)
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(T, typeVariableDeclaration)
+ listener: beginTypeVariable(T)
+ listener: handleTypeVariablesDefined(T, 1)
+ listener: handleNoType(T)
+ listener: endTypeVariable(>, 0, null, null)
+ listener: endTypeVariables(<, >)
+ parseGetterOrFormalParameters(>, bar, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(>, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(T, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(T, typeReference)
+ listener: handleNoTypeArguments(t)
+ listener: handleType(T, null)
+ ensureIdentifier(T, formalParameterDeclaration)
+ listener: handleIdentifier(t, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, t, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(main)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(main)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(main)
+ parseTopLevelMethod(;, null, ;, Instance of 'NoType', null, main)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleNoType(;)
+ ensureIdentifier(;, topLevelFunctionDeclaration)
+ listener: handleIdentifier(main, topLevelFunctionDeclaration)
+ parseMethodTypeVar(main)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(main, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, Function)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclaration({, false)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(f1)
+ parseExpressionWithoutCascade(=)
+ parsePrecedenceExpression(=, 1, false)
+ parseUnaryExpression(=, false)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ parseArgumentsOpt(foo)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Function, ?)
+ listener: beginVariablesDeclaration(f1, null, null)
+ parseVariablesDeclarationRest(?, true)
+ parseOptionallyInitializedIdentifier(?)
+ ensureIdentifier(?, localVariableDeclaration)
+ listener: handleIdentifier(f1, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f1)
+ parseVariableInitializerOpt(f1)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(foo, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(foo)
+ listener: handleNoArguments(;)
+ listener: handleSend(foo, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f1)
+ ensureSemicolon(foo)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, f1)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f1)
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseSendOrFunctionLiteral(;, expression)
+ parseSend(;, expression)
+ ensureIdentifier(;, expression)
+ listener: handleIdentifier(f1, expression)
+ listener: handleNoTypeArguments(!)
+ parseArgumentsOpt(f1)
+ listener: handleNoArguments(!)
+ listener: handleSend(f1, !)
+ listener: handleNonNullAssertExpression(!)
+ parseArgumentOrIndexStar(!, Instance of 'NoTypeParamOrArg')
+ listener: handleNoTypeArguments(()
+ parseArguments(!)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ listener: endArguments(1, (, ))
+ listener: handleSend((, ))
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, Function)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclaration(;, false)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(f2)
+ listener: handleType(Function, null)
+ listener: beginVariablesDeclaration(f2, null, null)
+ parseVariablesDeclarationRest(Function, true)
+ parseOptionallyInitializedIdentifier(Function)
+ ensureIdentifier(Function, localVariableDeclaration)
+ listener: handleIdentifier(f2, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f2)
+ parseVariableInitializerOpt(f2)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(bar, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(bar)
+ listener: handleNoArguments(;)
+ listener: handleSend(bar, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f2)
+ ensureSemicolon(bar)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, f2)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseSendOrFunctionLiteral(;, expression)
+ parseSend(;, expression)
+ ensureIdentifier(;, expression)
+ listener: handleIdentifier(f2, expression)
+ listener: handleNonNullAssertExpression(!)
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(int, null)
+ listener: endTypeArguments(1, <, >)
+ parseArgumentsOpt(>)
+ parseArguments(>)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ listener: endArguments(1, (, ))
+ listener: handleSend(f2, ;)
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(4, {, })
+ listener: endTopLevelMethod(main, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(Object)
+ listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.parser.expect
new file mode 100644
index 0000000..85afc92
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.parser.expect
@@ -0,0 +1,23 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+Function? f1 = foo;
+f1!(42);
+
+Function f2 = bar;
+f2!<int>(42);
+}
+
+
+Object[StringToken]?[SimpleToken] foo[StringToken]([BeginToken]int[StringToken] i[StringToken])[SimpleToken] =>[SimpleToken] "42"[StringToken];[SimpleToken]
+Object[StringToken]?[SimpleToken] bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken]T[StringToken] t[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken]?[SimpleToken] f1[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+f1[StringToken]![SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]![SimpleToken]<[BeginToken]int[StringToken]>[SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.scanner.expect
new file mode 100644
index 0000000..85afc92
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776.dart.scanner.expect
@@ -0,0 +1,23 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+Function? f1 = foo;
+f1!(42);
+
+Function f2 = bar;
+f2!<int>(42);
+}
+
+
+Object[StringToken]?[SimpleToken] foo[StringToken]([BeginToken]int[StringToken] i[StringToken])[SimpleToken] =>[SimpleToken] "42"[StringToken];[SimpleToken]
+Object[StringToken]?[SimpleToken] bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken]T[StringToken] t[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken]?[SimpleToken] f1[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+f1[StringToken]![SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]![SimpleToken]<[BeginToken]int[StringToken]>[SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart
new file mode 100644
index 0000000..e8a92a4
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart
@@ -0,0 +1,10 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+ Function? f1 = foo;
+ f1!(42);
+
+ Function f2 = bar;
+ f2<int>(42);
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.expect
new file mode 100644
index 0000000..721e3a4
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.expect
@@ -0,0 +1,129 @@
+beginCompilationUnit(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Object, ?)
+ handleIdentifier(foo, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(i)
+ handleType(int, null)
+ handleIdentifier(i, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginLiteralString("42")
+ endLiteralString(0, ;)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(;, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Object, ?)
+ handleIdentifier(bar, topLevelFunctionDeclaration)
+ beginTypeVariables(<)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ handleIdentifier(T, typeVariableDeclaration)
+ beginTypeVariable(T)
+ handleTypeVariablesDefined(T, 1)
+ handleNoType(T)
+ endTypeVariable(>, 0, null, null)
+ endTypeVariables(<, >)
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ beginFormalParameter(T, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(T, typeReference)
+ handleNoTypeArguments(t)
+ handleType(T, null)
+ handleIdentifier(t, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, t, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(main)
+ beginMetadataStar(main)
+ endMetadataStar(0)
+ beginTopLevelMember(main)
+ beginTopLevelMethod(;, null)
+ handleNoType(;)
+ handleIdentifier(main, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Function, ?)
+ beginVariablesDeclaration(f1, null, null)
+ handleIdentifier(f1, localVariableDeclaration)
+ beginInitializedIdentifier(f1)
+ beginVariableInitializer(=)
+ handleIdentifier(foo, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(foo, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f1)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f1, expression)
+ handleNoTypeArguments(!)
+ handleNoArguments(!)
+ handleSend(f1, !)
+ handleNonNullAssertExpression(!)
+ handleNoTypeArguments(()
+ beginArguments(()
+ handleLiteralInt(42)
+ endArguments(1, (, ))
+ handleSend((, ))
+ handleExpressionStatement(;)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(f2)
+ handleType(Function, null)
+ beginVariablesDeclaration(f2, null, null)
+ handleIdentifier(f2, localVariableDeclaration)
+ beginInitializedIdentifier(f2)
+ beginVariableInitializer(=)
+ handleIdentifier(bar, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(bar, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f2)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f2, expression)
+ beginTypeArguments(<)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(>)
+ handleType(int, null)
+ endTypeArguments(1, <, >)
+ beginArguments(()
+ handleLiteralInt(42)
+ endArguments(1, (, ))
+ handleSend(f2, ;)
+ handleExpressionStatement(;)
+ endBlockFunctionBody(4, {, })
+ endTopLevelMethod(main, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.intertwined.expect
new file mode 100644
index 0000000..2fb237b
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.intertwined.expect
@@ -0,0 +1,285 @@
+parseUnit(Object)
+ skipErrorTokens(Object)
+ listener: beginCompilationUnit(Object)
+ syntheticPreviousToken(Object)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(, null, , Instance of 'SimpleNullableType', null, foo)
+ listener: beginTopLevelMethod(, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Object, ?)
+ ensureIdentifier(?, topLevelFunctionDeclaration)
+ listener: handleIdentifier(foo, topLevelFunctionDeclaration)
+ parseMethodTypeVar(foo)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo, foo, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(foo, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(i)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(i, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralString(=>)
+ parseSingleLiteralString(=>)
+ listener: beginLiteralString("42")
+ listener: endLiteralString(0, ;)
+ ensureSemicolon("42")
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(Object)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(;, null, ;, Instance of 'SimpleNullableType', null, bar)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Object, ?)
+ ensureIdentifier(?, topLevelFunctionDeclaration)
+ listener: handleIdentifier(bar, topLevelFunctionDeclaration)
+ parseMethodTypeVar(bar)
+ listener: beginTypeVariables(<)
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(T, typeVariableDeclaration)
+ listener: beginTypeVariable(T)
+ listener: handleTypeVariablesDefined(T, 1)
+ listener: handleNoType(T)
+ listener: endTypeVariable(>, 0, null, null)
+ listener: endTypeVariables(<, >)
+ parseGetterOrFormalParameters(>, bar, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(>, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(T, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(T, typeReference)
+ listener: handleNoTypeArguments(t)
+ listener: handleType(T, null)
+ ensureIdentifier(T, formalParameterDeclaration)
+ listener: handleIdentifier(t, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, t, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(main)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(main)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(main)
+ parseTopLevelMethod(;, null, ;, Instance of 'NoType', null, main)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleNoType(;)
+ ensureIdentifier(;, topLevelFunctionDeclaration)
+ listener: handleIdentifier(main, topLevelFunctionDeclaration)
+ parseMethodTypeVar(main)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(main, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, Function)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclaration({, false)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(f1)
+ parseExpressionWithoutCascade(=)
+ parsePrecedenceExpression(=, 1, false)
+ parseUnaryExpression(=, false)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ parseArgumentsOpt(foo)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Function, ?)
+ listener: beginVariablesDeclaration(f1, null, null)
+ parseVariablesDeclarationRest(?, true)
+ parseOptionallyInitializedIdentifier(?)
+ ensureIdentifier(?, localVariableDeclaration)
+ listener: handleIdentifier(f1, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f1)
+ parseVariableInitializerOpt(f1)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(foo, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(foo)
+ listener: handleNoArguments(;)
+ listener: handleSend(foo, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f1)
+ ensureSemicolon(foo)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, f1)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f1)
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseSendOrFunctionLiteral(;, expression)
+ parseSend(;, expression)
+ ensureIdentifier(;, expression)
+ listener: handleIdentifier(f1, expression)
+ listener: handleNoTypeArguments(!)
+ parseArgumentsOpt(f1)
+ listener: handleNoArguments(!)
+ listener: handleSend(f1, !)
+ listener: handleNonNullAssertExpression(!)
+ parseArgumentOrIndexStar(!, Instance of 'NoTypeParamOrArg')
+ listener: handleNoTypeArguments(()
+ parseArguments(!)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ listener: endArguments(1, (, ))
+ listener: handleSend((, ))
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, Function)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclaration(;, false)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(f2)
+ listener: handleType(Function, null)
+ listener: beginVariablesDeclaration(f2, null, null)
+ parseVariablesDeclarationRest(Function, true)
+ parseOptionallyInitializedIdentifier(Function)
+ ensureIdentifier(Function, localVariableDeclaration)
+ listener: handleIdentifier(f2, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f2)
+ parseVariableInitializerOpt(f2)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(bar, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(bar)
+ listener: handleNoArguments(;)
+ listener: handleSend(bar, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f2)
+ ensureSemicolon(bar)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, f2)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseSendOrFunctionLiteral(;, expression)
+ looksLikeFunctionBody(;)
+ parseSend(;, expression)
+ ensureIdentifier(;, expression)
+ listener: handleIdentifier(f2, expression)
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(int, null)
+ listener: endTypeArguments(1, <, >)
+ parseArgumentsOpt(>)
+ parseArguments(>)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ listener: endArguments(1, (, ))
+ listener: handleSend(f2, ;)
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(4, {, })
+ listener: endTopLevelMethod(main, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(Object)
+ listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.parser.expect
new file mode 100644
index 0000000..7d382f2
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.parser.expect
@@ -0,0 +1,23 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+Function? f1 = foo;
+f1!(42);
+
+Function f2 = bar;
+f2<int>(42);
+}
+
+
+Object[StringToken]?[SimpleToken] foo[StringToken]([BeginToken]int[StringToken] i[StringToken])[SimpleToken] =>[SimpleToken] "42"[StringToken];[SimpleToken]
+Object[StringToken]?[SimpleToken] bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken]T[StringToken] t[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken]?[SimpleToken] f1[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+f1[StringToken]![SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]<[BeginToken]int[StringToken]>[SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.scanner.expect
new file mode 100644
index 0000000..7d382f2
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime1.dart.scanner.expect
@@ -0,0 +1,23 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+Function? f1 = foo;
+f1!(42);
+
+Function f2 = bar;
+f2<int>(42);
+}
+
+
+Object[StringToken]?[SimpleToken] foo[StringToken]([BeginToken]int[StringToken] i[StringToken])[SimpleToken] =>[SimpleToken] "42"[StringToken];[SimpleToken]
+Object[StringToken]?[SimpleToken] bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken]T[StringToken] t[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken]?[SimpleToken] f1[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+f1[StringToken]![SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]<[BeginToken]int[StringToken]>[SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart
new file mode 100644
index 0000000..1dc19a5
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart
@@ -0,0 +1,10 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+ Function? f1 = foo;
+ f1!(42);
+
+ Function f2 = bar;
+ (f2!)<int>(42);
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.expect
new file mode 100644
index 0000000..76b42cb
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.expect
@@ -0,0 +1,134 @@
+beginCompilationUnit(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Object, ?)
+ handleIdentifier(foo, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(i)
+ handleType(int, null)
+ handleIdentifier(i, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginLiteralString("42")
+ endLiteralString(0, ;)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(;, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Object, ?)
+ handleIdentifier(bar, topLevelFunctionDeclaration)
+ beginTypeVariables(<)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ handleIdentifier(T, typeVariableDeclaration)
+ beginTypeVariable(T)
+ handleTypeVariablesDefined(T, 1)
+ handleNoType(T)
+ endTypeVariable(>, 0, null, null)
+ endTypeVariables(<, >)
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ beginFormalParameter(T, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(T, typeReference)
+ handleNoTypeArguments(t)
+ handleType(T, null)
+ handleIdentifier(t, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, t, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(main)
+ beginMetadataStar(main)
+ endMetadataStar(0)
+ beginTopLevelMember(main)
+ beginTopLevelMethod(;, null)
+ handleNoType(;)
+ handleIdentifier(main, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(?)
+ handleType(Function, ?)
+ beginVariablesDeclaration(f1, null, null)
+ handleIdentifier(f1, localVariableDeclaration)
+ beginInitializedIdentifier(f1)
+ beginVariableInitializer(=)
+ handleIdentifier(foo, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(foo, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f1)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f1, expression)
+ handleNoTypeArguments(!)
+ handleNoArguments(!)
+ handleSend(f1, !)
+ handleNonNullAssertExpression(!)
+ handleNoTypeArguments(()
+ beginArguments(()
+ handleLiteralInt(42)
+ endArguments(1, (, ))
+ handleSend((, ))
+ handleExpressionStatement(;)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(f2)
+ handleType(Function, null)
+ beginVariablesDeclaration(f2, null, null)
+ handleIdentifier(f2, localVariableDeclaration)
+ beginInitializedIdentifier(f2)
+ beginVariableInitializer(=)
+ handleIdentifier(bar, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(bar, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f2)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f2, expression)
+ handleNoTypeArguments(!)
+ handleNoArguments(!)
+ handleSend(f2, !)
+ handleNonNullAssertExpression(!)
+ handleParenthesizedExpression(()
+ beginTypeArguments(<)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(>)
+ handleType(int, null)
+ endTypeArguments(1, <, >)
+ beginArguments(()
+ handleLiteralInt(42)
+ endArguments(1, (, ))
+ handleSend((, ))
+ handleExpressionStatement(;)
+ endBlockFunctionBody(4, {, })
+ endTopLevelMethod(main, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.intertwined.expect
new file mode 100644
index 0000000..1b497087
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.intertwined.expect
@@ -0,0 +1,300 @@
+parseUnit(Object)
+ skipErrorTokens(Object)
+ listener: beginCompilationUnit(Object)
+ syntheticPreviousToken(Object)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(, null, , Instance of 'SimpleNullableType', null, foo)
+ listener: beginTopLevelMethod(, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Object, ?)
+ ensureIdentifier(?, topLevelFunctionDeclaration)
+ listener: handleIdentifier(foo, topLevelFunctionDeclaration)
+ parseMethodTypeVar(foo)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo, foo, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(foo, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(i)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(i, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralString(=>)
+ parseSingleLiteralString(=>)
+ listener: beginLiteralString("42")
+ listener: endLiteralString(0, ;)
+ ensureSemicolon("42")
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(Object)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(;, null, ;, Instance of 'SimpleNullableType', null, bar)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Object, ?)
+ ensureIdentifier(?, topLevelFunctionDeclaration)
+ listener: handleIdentifier(bar, topLevelFunctionDeclaration)
+ parseMethodTypeVar(bar)
+ listener: beginTypeVariables(<)
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(T, typeVariableDeclaration)
+ listener: beginTypeVariable(T)
+ listener: handleTypeVariablesDefined(T, 1)
+ listener: handleNoType(T)
+ listener: endTypeVariable(>, 0, null, null)
+ listener: endTypeVariables(<, >)
+ parseGetterOrFormalParameters(>, bar, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(>, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(T, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(T, typeReference)
+ listener: handleNoTypeArguments(t)
+ listener: handleType(T, null)
+ ensureIdentifier(T, formalParameterDeclaration)
+ listener: handleIdentifier(t, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, t, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(main)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(main)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(main)
+ parseTopLevelMethod(;, null, ;, Instance of 'NoType', null, main)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleNoType(;)
+ ensureIdentifier(;, topLevelFunctionDeclaration)
+ listener: handleIdentifier(main, topLevelFunctionDeclaration)
+ parseMethodTypeVar(main)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(main, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, Function)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclaration({, false)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(f1)
+ parseExpressionWithoutCascade(=)
+ parsePrecedenceExpression(=, 1, false)
+ parseUnaryExpression(=, false)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ parseArgumentsOpt(foo)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(?)
+ listener: handleType(Function, ?)
+ listener: beginVariablesDeclaration(f1, null, null)
+ parseVariablesDeclarationRest(?, true)
+ parseOptionallyInitializedIdentifier(?)
+ ensureIdentifier(?, localVariableDeclaration)
+ listener: handleIdentifier(f1, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f1)
+ parseVariableInitializerOpt(f1)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(foo, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(foo)
+ listener: handleNoArguments(;)
+ listener: handleSend(foo, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f1)
+ ensureSemicolon(foo)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, f1)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f1)
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseSendOrFunctionLiteral(;, expression)
+ parseSend(;, expression)
+ ensureIdentifier(;, expression)
+ listener: handleIdentifier(f1, expression)
+ listener: handleNoTypeArguments(!)
+ parseArgumentsOpt(f1)
+ listener: handleNoArguments(!)
+ listener: handleSend(f1, !)
+ listener: handleNonNullAssertExpression(!)
+ parseArgumentOrIndexStar(!, Instance of 'NoTypeParamOrArg')
+ listener: handleNoTypeArguments(()
+ parseArguments(!)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ listener: endArguments(1, (, ))
+ listener: handleSend((, ))
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, Function)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclaration(;, false)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(f2)
+ listener: handleType(Function, null)
+ listener: beginVariablesDeclaration(f2, null, null)
+ parseVariablesDeclarationRest(Function, true)
+ parseOptionallyInitializedIdentifier(Function)
+ ensureIdentifier(Function, localVariableDeclaration)
+ listener: handleIdentifier(f2, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f2)
+ parseVariableInitializerOpt(f2)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(bar, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(bar)
+ listener: handleNoArguments(;)
+ listener: handleSend(bar, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f2)
+ ensureSemicolon(bar)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, ()
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclaration(;, false)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(()
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseParenthesizedExpressionOrFunctionLiteral(;)
+ parseParenthesizedExpression(;)
+ parseExpressionInParenthesis(;)
+ parseExpressionInParenthesisRest(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseSendOrFunctionLiteral((, expression)
+ parseSend((, expression)
+ ensureIdentifier((, expression)
+ listener: handleIdentifier(f2, expression)
+ listener: handleNoTypeArguments(!)
+ parseArgumentsOpt(f2)
+ listener: handleNoArguments(!)
+ listener: handleSend(f2, !)
+ listener: handleNonNullAssertExpression(!)
+ ensureCloseParen(!, ()
+ listener: handleParenthesizedExpression(()
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(int, null)
+ listener: endTypeArguments(1, <, >)
+ parseArgumentOrIndexStar(>, Instance of 'SimpleTypeArgument1')
+ parseArguments(>)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ listener: endArguments(1, (, ))
+ listener: handleSend((, ))
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(4, {, })
+ listener: endTopLevelMethod(main, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(Object)
+ listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.parser.expect
new file mode 100644
index 0000000..ed2d418
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.parser.expect
@@ -0,0 +1,23 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+Function? f1 = foo;
+f1!(42);
+
+Function f2 = bar;
+(f2!)<int>(42);
+}
+
+
+Object[StringToken]?[SimpleToken] foo[StringToken]([BeginToken]int[StringToken] i[StringToken])[SimpleToken] =>[SimpleToken] "42"[StringToken];[SimpleToken]
+Object[StringToken]?[SimpleToken] bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken]T[StringToken] t[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken]?[SimpleToken] f1[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+f1[StringToken]![SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+([BeginToken]f2[StringToken]![SimpleToken])[SimpleToken]<[BeginToken]int[StringToken]>[SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.scanner.expect
new file mode 100644
index 0000000..ed2d418
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime2.dart.scanner.expect
@@ -0,0 +1,23 @@
+Object? foo(int i) => "42";
+Object? bar<T>(T t) => 42;
+
+main() {
+Function? f1 = foo;
+f1!(42);
+
+Function f2 = bar;
+(f2!)<int>(42);
+}
+
+
+Object[StringToken]?[SimpleToken] foo[StringToken]([BeginToken]int[StringToken] i[StringToken])[SimpleToken] =>[SimpleToken] "42"[StringToken];[SimpleToken]
+Object[StringToken]?[SimpleToken] bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken]T[StringToken] t[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken]?[SimpleToken] f1[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+f1[StringToken]![SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+([BeginToken]f2[StringToken]![SimpleToken])[SimpleToken]<[BeginToken]int[StringToken]>[SimpleToken]([BeginToken]42[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart
new file mode 100644
index 0000000..a607c8d
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart
@@ -0,0 +1,6 @@
+Object bar<T1, T2>(T1 t1, T2 t2) => 42;
+
+main() {
+ Function f2 = bar;
+ f2!<int, String>(42, "42");
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.expect
new file mode 100644
index 0000000..5a45979
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.expect
@@ -0,0 +1,97 @@
+beginCompilationUnit(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(bar)
+ handleType(Object, null)
+ handleIdentifier(bar, topLevelFunctionDeclaration)
+ beginTypeVariables(<)
+ beginMetadataStar(T1)
+ endMetadataStar(0)
+ handleIdentifier(T1, typeVariableDeclaration)
+ beginTypeVariable(T1)
+ beginMetadataStar(T2)
+ endMetadataStar(0)
+ handleIdentifier(T2, typeVariableDeclaration)
+ beginTypeVariable(T2)
+ handleTypeVariablesDefined(T2, 2)
+ handleNoType(T2)
+ endTypeVariable(>, 1, null, null)
+ handleNoType(T1)
+ endTypeVariable(,, 0, null, null)
+ endTypeVariables(<, >)
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(T1)
+ endMetadataStar(0)
+ beginFormalParameter(T1, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(T1, typeReference)
+ handleNoTypeArguments(t1)
+ handleType(T1, null)
+ handleIdentifier(t1, formalParameterDeclaration)
+ handleFormalParameterWithoutValue(,)
+ endFormalParameter(null, null, t1, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ beginMetadataStar(T2)
+ endMetadataStar(0)
+ beginFormalParameter(T2, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(T2, typeReference)
+ handleNoTypeArguments(t2)
+ handleType(T2, null)
+ handleIdentifier(t2, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, t2, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(main)
+ beginMetadataStar(main)
+ endMetadataStar(0)
+ beginTopLevelMember(main)
+ beginTopLevelMethod(;, null)
+ handleNoType(;)
+ handleIdentifier(main, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(f2)
+ handleType(Function, null)
+ beginVariablesDeclaration(f2, null, null)
+ handleIdentifier(f2, localVariableDeclaration)
+ beginInitializedIdentifier(f2)
+ beginVariableInitializer(=)
+ handleIdentifier(bar, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(bar, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f2)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f2, expression)
+ handleNonNullAssertExpression(!)
+ beginTypeArguments(<)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(,)
+ handleType(int, null)
+ handleIdentifier(String, typeReference)
+ handleNoTypeArguments(>)
+ handleType(String, null)
+ endTypeArguments(2, <, >)
+ beginArguments(()
+ handleLiteralInt(42)
+ beginLiteralString("42")
+ endLiteralString(0, ))
+ endArguments(2, (, ))
+ handleSend(f2, ;)
+ handleExpressionStatement(;)
+ endBlockFunctionBody(2, {, })
+ endTopLevelMethod(main, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.intertwined.expect
new file mode 100644
index 0000000..a565c35
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.intertwined.expect
@@ -0,0 +1,191 @@
+parseUnit(Object)
+ skipErrorTokens(Object)
+ listener: beginCompilationUnit(Object)
+ syntheticPreviousToken(Object)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(, null, , Instance of 'SimpleType', null, bar)
+ listener: beginTopLevelMethod(, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(bar)
+ listener: handleType(Object, null)
+ ensureIdentifier(Object, topLevelFunctionDeclaration)
+ listener: handleIdentifier(bar, topLevelFunctionDeclaration)
+ parseMethodTypeVar(bar)
+ listener: beginTypeVariables(<)
+ parseMetadataStar(<)
+ listener: beginMetadataStar(T1)
+ listener: endMetadataStar(0)
+ ensureIdentifier(<, typeVariableDeclaration)
+ listener: handleIdentifier(T1, typeVariableDeclaration)
+ listener: beginTypeVariable(T1)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(T2)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(T2, typeVariableDeclaration)
+ listener: beginTypeVariable(T2)
+ listener: handleTypeVariablesDefined(T2, 2)
+ listener: handleNoType(T2)
+ listener: endTypeVariable(>, 1, null, null)
+ listener: handleNoType(T1)
+ listener: endTypeVariable(,, 0, null, null)
+ listener: endTypeVariables(<, >)
+ parseGetterOrFormalParameters(>, bar, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(>, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(T1)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(T1, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(T1, typeReference)
+ listener: handleNoTypeArguments(t1)
+ listener: handleType(T1, null)
+ ensureIdentifier(T1, formalParameterDeclaration)
+ listener: handleIdentifier(t1, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue(,)
+ listener: endFormalParameter(null, null, t1, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseFormalParameter(,, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(T2)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(T2, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(T2, typeReference)
+ listener: handleNoTypeArguments(t2)
+ listener: handleType(T2, null)
+ ensureIdentifier(T2, formalParameterDeclaration)
+ listener: handleIdentifier(t2, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, t2, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(main)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(main)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(main)
+ parseTopLevelMethod(;, null, ;, Instance of 'NoType', null, main)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleNoType(;)
+ ensureIdentifier(;, topLevelFunctionDeclaration)
+ listener: handleIdentifier(main, topLevelFunctionDeclaration)
+ parseMethodTypeVar(main)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(main, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, Function)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclaration({, false)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(f2)
+ listener: handleType(Function, null)
+ listener: beginVariablesDeclaration(f2, null, null)
+ parseVariablesDeclarationRest(Function, true)
+ parseOptionallyInitializedIdentifier(Function)
+ ensureIdentifier(Function, localVariableDeclaration)
+ listener: handleIdentifier(f2, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f2)
+ parseVariableInitializerOpt(f2)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(bar, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(bar)
+ listener: handleNoArguments(;)
+ listener: handleSend(bar, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f2)
+ ensureSemicolon(bar)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, f2)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseSendOrFunctionLiteral(;, expression)
+ parseSend(;, expression)
+ ensureIdentifier(;, expression)
+ listener: handleIdentifier(f2, expression)
+ listener: handleNonNullAssertExpression(!)
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(,)
+ listener: handleType(int, null)
+ listener: handleIdentifier(String, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(String, null)
+ listener: endTypeArguments(2, <, >)
+ parseArgumentsOpt(>)
+ parseArguments(>)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true)
+ parseUnaryExpression(,, true)
+ parsePrimary(,, expression)
+ parseLiteralString(,)
+ parseSingleLiteralString(,)
+ listener: beginLiteralString("42")
+ listener: endLiteralString(0, ))
+ listener: endArguments(2, (, ))
+ listener: handleSend(f2, ;)
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(2, {, })
+ listener: endTopLevelMethod(main, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(Object)
+ listener: endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.parser.expect
new file mode 100644
index 0000000..d1e654e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.parser.expect
@@ -0,0 +1,15 @@
+Object bar<T1, T2>(T1 t1, T2 t2) => 42;
+
+main() {
+Function f2 = bar;
+f2!<int, String>(42, "42");
+}
+
+
+Object[StringToken] bar[StringToken]<[BeginToken]T1[StringToken],[SimpleToken] T2[StringToken]>[SimpleToken]([BeginToken]T1[StringToken] t1[StringToken],[SimpleToken] T2[StringToken] t2[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]![SimpleToken]<[BeginToken]int[StringToken],[SimpleToken] String[StringToken]>[SimpleToken]([BeginToken]42[StringToken],[SimpleToken] "42"[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.scanner.expect
new file mode 100644
index 0000000..d1e654e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime3.dart.scanner.expect
@@ -0,0 +1,15 @@
+Object bar<T1, T2>(T1 t1, T2 t2) => 42;
+
+main() {
+Function f2 = bar;
+f2!<int, String>(42, "42");
+}
+
+
+Object[StringToken] bar[StringToken]<[BeginToken]T1[StringToken],[SimpleToken] T2[StringToken]>[SimpleToken]([BeginToken]T1[StringToken] t1[StringToken],[SimpleToken] T2[StringToken] t2[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]![SimpleToken]<[BeginToken]int[StringToken],[SimpleToken] String[StringToken]>[SimpleToken]([BeginToken]42[StringToken],[SimpleToken] "42"[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart
new file mode 100644
index 0000000..1bc0e9e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart
@@ -0,0 +1,6 @@
+Object bar<T1, T2>(T1 t1, T2 t2) => 42;
+
+main() {
+ Function f2 = bar;
+ f2<int, String>(42, "42");
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.expect
new file mode 100644
index 0000000..d0773b0
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.expect
@@ -0,0 +1,96 @@
+beginCompilationUnit(Object)
+ beginMetadataStar(Object)
+ endMetadataStar(0)
+ beginTopLevelMember(Object)
+ beginTopLevelMethod(, null)
+ handleIdentifier(Object, typeReference)
+ handleNoTypeArguments(bar)
+ handleType(Object, null)
+ handleIdentifier(bar, topLevelFunctionDeclaration)
+ beginTypeVariables(<)
+ beginMetadataStar(T1)
+ endMetadataStar(0)
+ handleIdentifier(T1, typeVariableDeclaration)
+ beginTypeVariable(T1)
+ beginMetadataStar(T2)
+ endMetadataStar(0)
+ handleIdentifier(T2, typeVariableDeclaration)
+ beginTypeVariable(T2)
+ handleTypeVariablesDefined(T2, 2)
+ handleNoType(T2)
+ endTypeVariable(>, 1, null, null)
+ handleNoType(T1)
+ endTypeVariable(,, 0, null, null)
+ endTypeVariables(<, >)
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(T1)
+ endMetadataStar(0)
+ beginFormalParameter(T1, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(T1, typeReference)
+ handleNoTypeArguments(t1)
+ handleType(T1, null)
+ handleIdentifier(t1, formalParameterDeclaration)
+ handleFormalParameterWithoutValue(,)
+ endFormalParameter(null, null, t1, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ beginMetadataStar(T2)
+ endMetadataStar(0)
+ beginFormalParameter(T2, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(T2, typeReference)
+ handleNoTypeArguments(t2)
+ handleType(T2, null)
+ handleIdentifier(t2, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, t2, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(Object, null, ;)
+ endTopLevelDeclaration(main)
+ beginMetadataStar(main)
+ endMetadataStar(0)
+ beginTopLevelMember(main)
+ beginTopLevelMethod(;, null)
+ handleNoType(;)
+ handleIdentifier(main, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginMetadataStar(Function)
+ endMetadataStar(0)
+ handleIdentifier(Function, typeReference)
+ handleNoTypeArguments(f2)
+ handleType(Function, null)
+ beginVariablesDeclaration(f2, null, null)
+ handleIdentifier(f2, localVariableDeclaration)
+ beginInitializedIdentifier(f2)
+ beginVariableInitializer(=)
+ handleIdentifier(bar, expression)
+ handleNoTypeArguments(;)
+ handleNoArguments(;)
+ handleSend(bar, ;)
+ endVariableInitializer(=)
+ endInitializedIdentifier(f2)
+ endVariablesDeclaration(1, ;)
+ handleIdentifier(f2, expression)
+ beginTypeArguments(<)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(,)
+ handleType(int, null)
+ handleIdentifier(String, typeReference)
+ handleNoTypeArguments(>)
+ handleType(String, null)
+ endTypeArguments(2, <, >)
+ beginArguments(()
+ handleLiteralInt(42)
+ beginLiteralString("42")
+ endLiteralString(0, ))
+ endArguments(2, (, ))
+ handleSend(f2, ;)
+ handleExpressionStatement(;)
+ endBlockFunctionBody(2, {, })
+ endTopLevelMethod(main, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.intertwined.expect
new file mode 100644
index 0000000..4e8a043
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.intertwined.expect
@@ -0,0 +1,191 @@
+parseUnit(Object)
+ skipErrorTokens(Object)
+ listener: beginCompilationUnit(Object)
+ syntheticPreviousToken(Object)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(Object)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(Object)
+ parseTopLevelMethod(, null, , Instance of 'SimpleType', null, bar)
+ listener: beginTopLevelMethod(, null)
+ listener: handleIdentifier(Object, typeReference)
+ listener: handleNoTypeArguments(bar)
+ listener: handleType(Object, null)
+ ensureIdentifier(Object, topLevelFunctionDeclaration)
+ listener: handleIdentifier(bar, topLevelFunctionDeclaration)
+ parseMethodTypeVar(bar)
+ listener: beginTypeVariables(<)
+ parseMetadataStar(<)
+ listener: beginMetadataStar(T1)
+ listener: endMetadataStar(0)
+ ensureIdentifier(<, typeVariableDeclaration)
+ listener: handleIdentifier(T1, typeVariableDeclaration)
+ listener: beginTypeVariable(T1)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(T2)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(T2, typeVariableDeclaration)
+ listener: beginTypeVariable(T2)
+ listener: handleTypeVariablesDefined(T2, 2)
+ listener: handleNoType(T2)
+ listener: endTypeVariable(>, 1, null, null)
+ listener: handleNoType(T1)
+ listener: endTypeVariable(,, 0, null, null)
+ listener: endTypeVariables(<, >)
+ parseGetterOrFormalParameters(>, bar, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(>, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(T1)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(T1, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(T1, typeReference)
+ listener: handleNoTypeArguments(t1)
+ listener: handleType(T1, null)
+ ensureIdentifier(T1, formalParameterDeclaration)
+ listener: handleIdentifier(t1, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue(,)
+ listener: endFormalParameter(null, null, t1, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseFormalParameter(,, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(T2)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(T2, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(T2, typeReference)
+ listener: handleNoTypeArguments(t2)
+ listener: handleType(T2, null)
+ ensureIdentifier(T2, formalParameterDeclaration)
+ listener: handleIdentifier(t2, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, t2, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(Object, null, ;)
+ listener: endTopLevelDeclaration(main)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(main)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(main)
+ parseTopLevelMethod(;, null, ;, Instance of 'NoType', null, main)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleNoType(;)
+ ensureIdentifier(;, topLevelFunctionDeclaration)
+ listener: handleIdentifier(main, topLevelFunctionDeclaration)
+ parseMethodTypeVar(main)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(main, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, Function)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclaration({, false)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ listener: beginMetadataStar(Function)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(Function, typeReference)
+ listener: handleNoTypeArguments(f2)
+ listener: handleType(Function, null)
+ listener: beginVariablesDeclaration(f2, null, null)
+ parseVariablesDeclarationRest(Function, true)
+ parseOptionallyInitializedIdentifier(Function)
+ ensureIdentifier(Function, localVariableDeclaration)
+ listener: handleIdentifier(f2, localVariableDeclaration)
+ listener: beginInitializedIdentifier(f2)
+ parseVariableInitializerOpt(f2)
+ listener: beginVariableInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ listener: handleIdentifier(bar, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(bar)
+ listener: handleNoArguments(;)
+ listener: handleSend(bar, ;)
+ listener: endVariableInitializer(=)
+ listener: endInitializedIdentifier(f2)
+ ensureSemicolon(bar)
+ listener: endVariablesDeclaration(1, ;)
+ notEofOrValue(}, f2)
+ parseStatement(;)
+ parseStatementX(;)
+ parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+ looksLikeLocalFunction(f2)
+ parseExpressionStatement(;)
+ parseExpression(;)
+ parsePrecedenceExpression(;, 1, true)
+ parseUnaryExpression(;, true)
+ parsePrimary(;, expression)
+ parseSendOrFunctionLiteral(;, expression)
+ looksLikeFunctionBody(;)
+ parseSend(;, expression)
+ ensureIdentifier(;, expression)
+ listener: handleIdentifier(f2, expression)
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(,)
+ listener: handleType(int, null)
+ listener: handleIdentifier(String, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(String, null)
+ listener: endTypeArguments(2, <, >)
+ parseArgumentsOpt(>)
+ parseArguments(>)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralInt(()
+ listener: handleLiteralInt(42)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true)
+ parseUnaryExpression(,, true)
+ parsePrimary(,, expression)
+ parseLiteralString(,)
+ parseSingleLiteralString(,)
+ listener: beginLiteralString("42")
+ listener: endLiteralString(0, ))
+ listener: endArguments(2, (, ))
+ listener: handleSend(f2, ;)
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(2, {, })
+ listener: endTopLevelMethod(main, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(Object)
+ listener: endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.parser.expect
new file mode 100644
index 0000000..562a360
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.parser.expect
@@ -0,0 +1,15 @@
+Object bar<T1, T2>(T1 t1, T2 t2) => 42;
+
+main() {
+Function f2 = bar;
+f2<int, String>(42, "42");
+}
+
+
+Object[StringToken] bar[StringToken]<[BeginToken]T1[StringToken],[SimpleToken] T2[StringToken]>[SimpleToken]([BeginToken]T1[StringToken] t1[StringToken],[SimpleToken] T2[StringToken] t2[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]<[BeginToken]int[StringToken],[SimpleToken] String[StringToken]>[SimpleToken]([BeginToken]42[StringToken],[SimpleToken] "42"[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.scanner.expect
new file mode 100644
index 0000000..562a360
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime4.dart.scanner.expect
@@ -0,0 +1,15 @@
+Object bar<T1, T2>(T1 t1, T2 t2) => 42;
+
+main() {
+Function f2 = bar;
+f2<int, String>(42, "42");
+}
+
+
+Object[StringToken] bar[StringToken]<[BeginToken]T1[StringToken],[SimpleToken] T2[StringToken]>[SimpleToken]([BeginToken]T1[StringToken] t1[StringToken],[SimpleToken] T2[StringToken] t2[StringToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Function[KeywordToken] f2[StringToken] =[SimpleToken] bar[StringToken];[SimpleToken]
+f2[StringToken]<[BeginToken]int[StringToken],[SimpleToken] String[StringToken]>[SimpleToken]([BeginToken]42[StringToken],[SimpleToken] "42"[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart
new file mode 100644
index 0000000..48f0bfd
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart
@@ -0,0 +1,2 @@
+foo!() => 42;
+bar!<T>() => 42;
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.expect
new file mode 100644
index 0000000..3804bfe
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.expect
@@ -0,0 +1,50 @@
+Problems reported:
+
+parser/nnbd/issue_39776_prime5:1:4: Unexpected token '!'.
+foo!() => 42;
+ ^
+
+parser/nnbd/issue_39776_prime5:2:4: Unexpected token '!'.
+bar!<T>() => 42;
+ ^
+
+beginCompilationUnit(foo)
+ beginMetadataStar(foo)
+ endMetadataStar(0)
+ beginTopLevelMember(foo)
+ beginTopLevelMethod(, null)
+ handleNoType()
+ handleIdentifier(foo, topLevelFunctionDeclaration)
+ handleRecoverableError(Message[UnexpectedToken, Unexpected token '!'., null, {token: !}], !, !)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(foo, null, ;)
+ endTopLevelDeclaration(bar)
+ beginMetadataStar(bar)
+ endMetadataStar(0)
+ beginTopLevelMember(bar)
+ beginTopLevelMethod(;, null)
+ handleNoType(;)
+ handleIdentifier(bar, topLevelFunctionDeclaration)
+ handleRecoverableError(Message[UnexpectedToken, Unexpected token '!'., null, {token: !}], !, !)
+ beginTypeVariables(<)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ handleIdentifier(T, typeVariableDeclaration)
+ beginTypeVariable(T)
+ handleTypeVariablesDefined(T, 1)
+ handleNoType(T)
+ endTypeVariable(>, 0, null, null)
+ endTypeVariables(<, >)
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(bar, null, ;)
+ endTopLevelDeclaration()
+endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.intertwined.expect
new file mode 100644
index 0000000..80648cc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.intertwined.expect
@@ -0,0 +1,86 @@
+parseUnit(foo)
+ skipErrorTokens(foo)
+ listener: beginCompilationUnit(foo)
+ syntheticPreviousToken(foo)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(foo)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(foo)
+ parseTopLevelMethod(, null, , Instance of 'NoType', null, foo)
+ listener: beginTopLevelMethod(, null)
+ listener: handleNoType()
+ ensureIdentifier(, topLevelFunctionDeclaration)
+ listener: handleIdentifier(foo, topLevelFunctionDeclaration)
+ parseMethodTypeVar(foo)
+ reportRecoverableErrorWithToken(!, Instance of 'Template<(Token) => Message>')
+ listener: handleRecoverableError(Message[UnexpectedToken, Unexpected token '!'., null, {token: !}], !, !)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(!, foo, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(!, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(foo, null, ;)
+ listener: endTopLevelDeclaration(bar)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(bar)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(bar)
+ parseTopLevelMethod(;, null, ;, Instance of 'NoType', null, bar)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleNoType(;)
+ ensureIdentifier(;, topLevelFunctionDeclaration)
+ listener: handleIdentifier(bar, topLevelFunctionDeclaration)
+ parseMethodTypeVar(bar)
+ reportRecoverableErrorWithToken(!, Instance of 'Template<(Token) => Message>')
+ listener: handleRecoverableError(Message[UnexpectedToken, Unexpected token '!'., null, {token: !}], !, !)
+ listener: beginTypeVariables(<)
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(T, typeVariableDeclaration)
+ listener: beginTypeVariable(T)
+ listener: handleTypeVariablesDefined(T, 1)
+ listener: handleNoType(T)
+ listener: endTypeVariable(>, 0, null, null)
+ listener: endTypeVariables(<, >)
+ parseGetterOrFormalParameters(>, bar, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(>, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(bar, null, ;)
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(foo)
+ listener: endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.parser.expect
new file mode 100644
index 0000000..8eb1e98
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.parser.expect
@@ -0,0 +1,7 @@
+foo!() => 42;
+bar!<T>() => 42;
+
+
+foo[StringToken]![SimpleToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+bar[StringToken]![SimpleToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.scanner.expect
new file mode 100644
index 0000000..8eb1e98
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime5.dart.scanner.expect
@@ -0,0 +1,7 @@
+foo!() => 42;
+bar!<T>() => 42;
+
+
+foo[StringToken]![SimpleToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+bar[StringToken]![SimpleToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart
new file mode 100644
index 0000000..31e50bf
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart
@@ -0,0 +1,2 @@
+foo() => 42;
+bar<T>() => 42;
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.expect
new file mode 100644
index 0000000..f0bd214
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.expect
@@ -0,0 +1,38 @@
+beginCompilationUnit(foo)
+ beginMetadataStar(foo)
+ endMetadataStar(0)
+ beginTopLevelMember(foo)
+ beginTopLevelMethod(, null)
+ handleNoType()
+ handleIdentifier(foo, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(foo, null, ;)
+ endTopLevelDeclaration(bar)
+ beginMetadataStar(bar)
+ endMetadataStar(0)
+ beginTopLevelMember(bar)
+ beginTopLevelMethod(;, null)
+ handleNoType(;)
+ handleIdentifier(bar, topLevelFunctionDeclaration)
+ beginTypeVariables(<)
+ beginMetadataStar(T)
+ endMetadataStar(0)
+ handleIdentifier(T, typeVariableDeclaration)
+ beginTypeVariable(T)
+ handleTypeVariablesDefined(T, 1)
+ handleNoType(T)
+ endTypeVariable(>, 0, null, null)
+ endTypeVariables(<, >)
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ handleLiteralInt(42)
+ handleExpressionFunctionBody(=>, ;)
+ endTopLevelMethod(bar, null, ;)
+ endTopLevelDeclaration()
+endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.intertwined.expect
new file mode 100644
index 0000000..ecc48b8
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.intertwined.expect
@@ -0,0 +1,82 @@
+parseUnit(foo)
+ skipErrorTokens(foo)
+ listener: beginCompilationUnit(foo)
+ syntheticPreviousToken(foo)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(foo)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(foo)
+ parseTopLevelMethod(, null, , Instance of 'NoType', null, foo)
+ listener: beginTopLevelMethod(, null)
+ listener: handleNoType()
+ ensureIdentifier(, topLevelFunctionDeclaration)
+ listener: handleIdentifier(foo, topLevelFunctionDeclaration)
+ parseMethodTypeVar(foo)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo, foo, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(foo, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(foo, null, ;)
+ listener: endTopLevelDeclaration(bar)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(bar)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(;)
+ listener: beginTopLevelMember(bar)
+ parseTopLevelMethod(;, null, ;, Instance of 'NoType', null, bar)
+ listener: beginTopLevelMethod(;, null)
+ listener: handleNoType(;)
+ ensureIdentifier(;, topLevelFunctionDeclaration)
+ listener: handleIdentifier(bar, topLevelFunctionDeclaration)
+ parseMethodTypeVar(bar)
+ listener: beginTypeVariables(<)
+ listener: beginMetadataStar(T)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(T, typeVariableDeclaration)
+ listener: beginTypeVariable(T)
+ listener: handleTypeVariablesDefined(T, 1)
+ listener: handleNoType(T)
+ listener: endTypeVariable(>, 0, null, null)
+ listener: endTypeVariables(<, >)
+ parseGetterOrFormalParameters(>, bar, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(>, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ parseExpressionFunctionBody(=>, false)
+ parseExpression(=>)
+ parsePrecedenceExpression(=>, 1, true)
+ parseUnaryExpression(=>, true)
+ parsePrimary(=>, expression)
+ parseLiteralInt(=>)
+ listener: handleLiteralInt(42)
+ ensureSemicolon(42)
+ listener: handleExpressionFunctionBody(=>, ;)
+ inGenerator()
+ listener: endTopLevelMethod(bar, null, ;)
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(foo)
+ listener: endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.parser.expect
new file mode 100644
index 0000000..0cb7627
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.parser.expect
@@ -0,0 +1,7 @@
+foo() => 42;
+bar<T>() => 42;
+
+
+foo[StringToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.scanner.expect
new file mode 100644
index 0000000..0cb7627
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39776_prime6.dart.scanner.expect
@@ -0,0 +1,7 @@
+foo() => 42;
+bar<T>() => 42;
+
+
+foo[StringToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+bar[StringToken]<[BeginToken]T[StringToken]>[SimpleToken]([BeginToken])[SimpleToken] =>[SimpleToken] 42[StringToken];[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart
new file mode 100644
index 0000000..66a84ff
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart
@@ -0,0 +1,8 @@
+class X {
+ late x1;
+ static late x2;
+ covariant late x3;
+ late x4 = 0;
+ static late x5 = 0;
+ covariant late x6 = 0;
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.expect
new file mode 100644
index 0000000..65df0a7
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.expect
@@ -0,0 +1,103 @@
+Problems reported:
+
+parser/nnbd/issue_39858:2:8: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ late x1;
+ ^^
+
+parser/nnbd/issue_39858:3:15: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ static late x2;
+ ^^
+
+parser/nnbd/issue_39858:4:18: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ covariant late x3;
+ ^^
+
+parser/nnbd/issue_39858:5:8: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ late x4 = 0;
+ ^^
+
+parser/nnbd/issue_39858:6:15: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ static late x5 = 0;
+ ^^
+
+parser/nnbd/issue_39858:7:18: Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ covariant late x6 = 0;
+ ^^
+
+beginCompilationUnit(class)
+ beginMetadataStar(class)
+ endMetadataStar(0)
+ beginClassOrNamedMixinApplicationPrelude(class)
+ handleIdentifier(X, classOrMixinDeclaration)
+ handleNoTypeVariables({)
+ beginClassDeclaration(class, null, X)
+ handleNoType(X)
+ handleClassExtends(null)
+ handleClassNoWithClause()
+ handleClassOrMixinImplements(null, 0)
+ handleClassHeader(class, class, null)
+ beginClassOrMixinBody(DeclarationKind.Class, {)
+ beginMetadataStar(late)
+ endMetadataStar(0)
+ beginMember()
+ handleRecoverableError(MissingConstFinalVarOrType, x1, x1)
+ handleNoType(late)
+ handleIdentifier(x1, fieldDeclaration)
+ handleNoFieldInitializer(;)
+ endClassFields(null, null, late, null, 1, late, ;)
+ endMember()
+ beginMetadataStar(static)
+ endMetadataStar(0)
+ beginMember()
+ handleRecoverableError(MissingConstFinalVarOrType, x2, x2)
+ handleNoType(late)
+ handleIdentifier(x2, fieldDeclaration)
+ handleNoFieldInitializer(;)
+ endClassFields(static, null, late, null, 1, static, ;)
+ endMember()
+ beginMetadataStar(covariant)
+ endMetadataStar(0)
+ beginMember()
+ handleRecoverableError(MissingConstFinalVarOrType, x3, x3)
+ handleNoType(late)
+ handleIdentifier(x3, fieldDeclaration)
+ handleNoFieldInitializer(;)
+ endClassFields(null, covariant, late, null, 1, covariant, ;)
+ endMember()
+ beginMetadataStar(late)
+ endMetadataStar(0)
+ beginMember()
+ handleRecoverableError(MissingConstFinalVarOrType, x4, x4)
+ handleNoType(late)
+ handleIdentifier(x4, fieldDeclaration)
+ beginFieldInitializer(=)
+ handleLiteralInt(0)
+ endFieldInitializer(=, ;)
+ endClassFields(null, null, late, null, 1, late, ;)
+endMember()
+beginMetadataStar(static)
+endMetadataStar(0)
+beginMember()
+ handleRecoverableError(MissingConstFinalVarOrType, x5, x5)
+ handleNoType(late)
+ handleIdentifier(x5, fieldDeclaration)
+ beginFieldInitializer(=)
+ handleLiteralInt(0)
+ endFieldInitializer(=, ;)
+endClassFields(static, null, late, null, 1, static, ;)
+endMember()
+beginMetadataStar(covariant)
+endMetadataStar(0)
+beginMember()
+handleRecoverableError(MissingConstFinalVarOrType, x6, x6)
+handleNoType(late)
+handleIdentifier(x6, fieldDeclaration)
+beginFieldInitializer(=)
+ handleLiteralInt(0)
+endFieldInitializer(=, ;)
+endClassFields(null, covariant, late, null, 1, covariant, ;)
+endMember()
+endClassOrMixinBody(DeclarationKind.Class, 6, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.intertwined.expect
new file mode 100644
index 0000000..ac34652
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.intertwined.expect
@@ -0,0 +1,151 @@
+parseUnit(class)
+ skipErrorTokens(class)
+ listener: beginCompilationUnit(class)
+ syntheticPreviousToken(class)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(class)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+ parseClassDeclarationModifiers(, class)
+ parseClassOrNamedMixinApplication(null, class)
+ listener: beginClassOrNamedMixinApplicationPrelude(class)
+ ensureIdentifier(class, classOrMixinDeclaration)
+ listener: handleIdentifier(X, classOrMixinDeclaration)
+ listener: handleNoTypeVariables({)
+ listener: beginClassDeclaration(class, null, X)
+ parseClass(X, class, class, X)
+ parseClassHeaderOpt(X, class, class)
+ parseClassExtendsOpt(X)
+ listener: handleNoType(X)
+ listener: handleClassExtends(null)
+ parseWithClauseOpt(X)
+ listener: handleClassNoWithClause()
+ parseClassOrMixinImplementsOpt(X)
+ listener: handleClassOrMixinImplements(null, 0)
+ listener: handleClassHeader(class, class, null)
+ parseClassOrMixinOrExtensionBody(X, DeclarationKind.Class, X)
+ listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+ notEofOrValue(}, late)
+ parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, X)
+ parseMetadataStar({)
+ listener: beginMetadataStar(late)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields({, null, null, null, late, null, late, Instance of 'NoType', x1, DeclarationKind.Class)
+ reportRecoverableError(x1, MissingConstFinalVarOrType)
+ listener: handleRecoverableError(MissingConstFinalVarOrType, x1, x1)
+ listener: handleNoType(late)
+ ensureIdentifier(late, fieldDeclaration)
+ listener: handleIdentifier(x1, fieldDeclaration)
+ parseFieldInitializerOpt(x1, x1, late, null, DeclarationKind.Class)
+ listener: handleNoFieldInitializer(;)
+ listener: endClassFields(null, null, late, null, 1, late, ;)
+ listener: endMember()
+ notEofOrValue(}, static)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(static)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, static, null, late, null, late, Instance of 'NoType', x2, DeclarationKind.Class)
+ reportRecoverableError(x2, MissingConstFinalVarOrType)
+ listener: handleRecoverableError(MissingConstFinalVarOrType, x2, x2)
+ listener: handleNoType(late)
+ ensureIdentifier(late, fieldDeclaration)
+ listener: handleIdentifier(x2, fieldDeclaration)
+ parseFieldInitializerOpt(x2, x2, late, null, DeclarationKind.Class)
+ listener: handleNoFieldInitializer(;)
+ listener: endClassFields(static, null, late, null, 1, static, ;)
+ listener: endMember()
+ notEofOrValue(}, covariant)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(covariant)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, null, covariant, late, null, late, Instance of 'NoType', x3, DeclarationKind.Class)
+ reportRecoverableError(x3, MissingConstFinalVarOrType)
+ listener: handleRecoverableError(MissingConstFinalVarOrType, x3, x3)
+ listener: handleNoType(late)
+ ensureIdentifier(late, fieldDeclaration)
+ listener: handleIdentifier(x3, fieldDeclaration)
+ parseFieldInitializerOpt(x3, x3, late, null, DeclarationKind.Class)
+ listener: handleNoFieldInitializer(;)
+ listener: endClassFields(null, covariant, late, null, 1, covariant, ;)
+ listener: endMember()
+ notEofOrValue(}, late)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(late)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, null, null, late, null, late, Instance of 'NoType', x4, DeclarationKind.Class)
+ reportRecoverableError(x4, MissingConstFinalVarOrType)
+ listener: handleRecoverableError(MissingConstFinalVarOrType, x4, x4)
+ listener: handleNoType(late)
+ ensureIdentifier(late, fieldDeclaration)
+ listener: handleIdentifier(x4, fieldDeclaration)
+ parseFieldInitializerOpt(x4, x4, late, null, DeclarationKind.Class)
+ listener: beginFieldInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseLiteralInt(=)
+ listener: handleLiteralInt(0)
+ listener: endFieldInitializer(=, ;)
+ listener: endClassFields(null, null, late, null, 1, late, ;)
+ listener: endMember()
+ notEofOrValue(}, static)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(static)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, static, null, late, null, late, Instance of 'NoType', x5, DeclarationKind.Class)
+ reportRecoverableError(x5, MissingConstFinalVarOrType)
+ listener: handleRecoverableError(MissingConstFinalVarOrType, x5, x5)
+ listener: handleNoType(late)
+ ensureIdentifier(late, fieldDeclaration)
+ listener: handleIdentifier(x5, fieldDeclaration)
+ parseFieldInitializerOpt(x5, x5, late, null, DeclarationKind.Class)
+ listener: beginFieldInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseLiteralInt(=)
+ listener: handleLiteralInt(0)
+ listener: endFieldInitializer(=, ;)
+ listener: endClassFields(static, null, late, null, 1, static, ;)
+ listener: endMember()
+ notEofOrValue(}, covariant)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(covariant)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, null, covariant, late, null, late, Instance of 'NoType', x6, DeclarationKind.Class)
+ reportRecoverableError(x6, MissingConstFinalVarOrType)
+ listener: handleRecoverableError(MissingConstFinalVarOrType, x6, x6)
+ listener: handleNoType(late)
+ ensureIdentifier(late, fieldDeclaration)
+ listener: handleIdentifier(x6, fieldDeclaration)
+ parseFieldInitializerOpt(x6, x6, late, null, DeclarationKind.Class)
+ listener: beginFieldInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseLiteralInt(=)
+ listener: handleLiteralInt(0)
+ listener: endFieldInitializer(=, ;)
+ listener: endClassFields(null, covariant, late, null, 1, covariant, ;)
+ listener: endMember()
+ notEofOrValue(}, })
+ listener: endClassOrMixinBody(DeclarationKind.Class, 6, {, })
+ listener: endClassDeclaration(class, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(class)
+ listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.parser.expect
new file mode 100644
index 0000000..13080f9
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.parser.expect
@@ -0,0 +1,19 @@
+class X {
+late x1;
+static late x2;
+covariant late x3;
+late x4 = 0;
+static late x5 = 0;
+covariant late x6 = 0;
+}
+
+
+class[KeywordToken] X[StringToken] {[BeginToken]
+late[KeywordToken] x1[StringToken];[SimpleToken]
+static[KeywordToken] late[KeywordToken] x2[StringToken];[SimpleToken]
+covariant[KeywordToken] late[KeywordToken] x3[StringToken];[SimpleToken]
+late[KeywordToken] x4[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+static[KeywordToken] late[KeywordToken] x5[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+covariant[KeywordToken] late[KeywordToken] x6[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.scanner.expect
new file mode 100644
index 0000000..13080f9
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858.dart.scanner.expect
@@ -0,0 +1,19 @@
+class X {
+late x1;
+static late x2;
+covariant late x3;
+late x4 = 0;
+static late x5 = 0;
+covariant late x6 = 0;
+}
+
+
+class[KeywordToken] X[StringToken] {[BeginToken]
+late[KeywordToken] x1[StringToken];[SimpleToken]
+static[KeywordToken] late[KeywordToken] x2[StringToken];[SimpleToken]
+covariant[KeywordToken] late[KeywordToken] x3[StringToken];[SimpleToken]
+late[KeywordToken] x4[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+static[KeywordToken] late[KeywordToken] x5[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+covariant[KeywordToken] late[KeywordToken] x6[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart
new file mode 100644
index 0000000..a4672b8
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart
@@ -0,0 +1,8 @@
+class X {
+ var x1;
+ static var x2;
+ covariant var x3;
+ var x4 = 0;
+ static var x5 = 0;
+ covariant var x6 = 0;
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.expect
new file mode 100644
index 0000000..d41f4e7
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.expect
@@ -0,0 +1,71 @@
+beginCompilationUnit(class)
+ beginMetadataStar(class)
+ endMetadataStar(0)
+ beginClassOrNamedMixinApplicationPrelude(class)
+ handleIdentifier(X, classOrMixinDeclaration)
+ handleNoTypeVariables({)
+ beginClassDeclaration(class, null, X)
+ handleNoType(X)
+ handleClassExtends(null)
+ handleClassNoWithClause()
+ handleClassOrMixinImplements(null, 0)
+ handleClassHeader(class, class, null)
+ beginClassOrMixinBody(DeclarationKind.Class, {)
+ beginMetadataStar(var)
+ endMetadataStar(0)
+ beginMember()
+ handleNoType(var)
+ handleIdentifier(x1, fieldDeclaration)
+ handleNoFieldInitializer(;)
+ endClassFields(null, null, null, var, 1, var, ;)
+ endMember()
+ beginMetadataStar(static)
+ endMetadataStar(0)
+ beginMember()
+ handleNoType(var)
+ handleIdentifier(x2, fieldDeclaration)
+ handleNoFieldInitializer(;)
+ endClassFields(static, null, null, var, 1, static, ;)
+ endMember()
+ beginMetadataStar(covariant)
+ endMetadataStar(0)
+ beginMember()
+ handleNoType(var)
+ handleIdentifier(x3, fieldDeclaration)
+ handleNoFieldInitializer(;)
+ endClassFields(null, covariant, null, var, 1, covariant, ;)
+ endMember()
+ beginMetadataStar(var)
+ endMetadataStar(0)
+ beginMember()
+ handleNoType(var)
+ handleIdentifier(x4, fieldDeclaration)
+ beginFieldInitializer(=)
+ handleLiteralInt(0)
+ endFieldInitializer(=, ;)
+ endClassFields(null, null, null, var, 1, var, ;)
+endMember()
+beginMetadataStar(static)
+endMetadataStar(0)
+beginMember()
+ handleNoType(var)
+ handleIdentifier(x5, fieldDeclaration)
+ beginFieldInitializer(=)
+ handleLiteralInt(0)
+ endFieldInitializer(=, ;)
+endClassFields(static, null, null, var, 1, static, ;)
+endMember()
+beginMetadataStar(covariant)
+endMetadataStar(0)
+beginMember()
+handleNoType(var)
+handleIdentifier(x6, fieldDeclaration)
+beginFieldInitializer(=)
+ handleLiteralInt(0)
+endFieldInitializer(=, ;)
+endClassFields(null, covariant, null, var, 1, covariant, ;)
+endMember()
+endClassOrMixinBody(DeclarationKind.Class, 6, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.intertwined.expect
new file mode 100644
index 0000000..f0ecb2d
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.intertwined.expect
@@ -0,0 +1,139 @@
+parseUnit(class)
+ skipErrorTokens(class)
+ listener: beginCompilationUnit(class)
+ syntheticPreviousToken(class)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(class)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+ parseClassDeclarationModifiers(, class)
+ parseClassOrNamedMixinApplication(null, class)
+ listener: beginClassOrNamedMixinApplicationPrelude(class)
+ ensureIdentifier(class, classOrMixinDeclaration)
+ listener: handleIdentifier(X, classOrMixinDeclaration)
+ listener: handleNoTypeVariables({)
+ listener: beginClassDeclaration(class, null, X)
+ parseClass(X, class, class, X)
+ parseClassHeaderOpt(X, class, class)
+ parseClassExtendsOpt(X)
+ listener: handleNoType(X)
+ listener: handleClassExtends(null)
+ parseWithClauseOpt(X)
+ listener: handleClassNoWithClause()
+ parseClassOrMixinImplementsOpt(X)
+ listener: handleClassOrMixinImplements(null, 0)
+ listener: handleClassHeader(class, class, null)
+ parseClassOrMixinOrExtensionBody(X, DeclarationKind.Class, X)
+ listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+ notEofOrValue(}, var)
+ parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, X)
+ parseMetadataStar({)
+ listener: beginMetadataStar(var)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields({, null, null, null, null, var, var, Instance of 'NoType', x1, DeclarationKind.Class)
+ listener: handleNoType(var)
+ ensureIdentifier(var, fieldDeclaration)
+ listener: handleIdentifier(x1, fieldDeclaration)
+ parseFieldInitializerOpt(x1, x1, null, var, DeclarationKind.Class)
+ listener: handleNoFieldInitializer(;)
+ listener: endClassFields(null, null, null, var, 1, var, ;)
+ listener: endMember()
+ notEofOrValue(}, static)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(static)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, static, null, null, var, var, Instance of 'NoType', x2, DeclarationKind.Class)
+ listener: handleNoType(var)
+ ensureIdentifier(var, fieldDeclaration)
+ listener: handleIdentifier(x2, fieldDeclaration)
+ parseFieldInitializerOpt(x2, x2, null, var, DeclarationKind.Class)
+ listener: handleNoFieldInitializer(;)
+ listener: endClassFields(static, null, null, var, 1, static, ;)
+ listener: endMember()
+ notEofOrValue(}, covariant)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(covariant)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, null, covariant, null, var, var, Instance of 'NoType', x3, DeclarationKind.Class)
+ listener: handleNoType(var)
+ ensureIdentifier(var, fieldDeclaration)
+ listener: handleIdentifier(x3, fieldDeclaration)
+ parseFieldInitializerOpt(x3, x3, null, var, DeclarationKind.Class)
+ listener: handleNoFieldInitializer(;)
+ listener: endClassFields(null, covariant, null, var, 1, covariant, ;)
+ listener: endMember()
+ notEofOrValue(}, var)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(var)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, null, null, null, var, var, Instance of 'NoType', x4, DeclarationKind.Class)
+ listener: handleNoType(var)
+ ensureIdentifier(var, fieldDeclaration)
+ listener: handleIdentifier(x4, fieldDeclaration)
+ parseFieldInitializerOpt(x4, x4, null, var, DeclarationKind.Class)
+ listener: beginFieldInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseLiteralInt(=)
+ listener: handleLiteralInt(0)
+ listener: endFieldInitializer(=, ;)
+ listener: endClassFields(null, null, null, var, 1, var, ;)
+ listener: endMember()
+ notEofOrValue(}, static)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(static)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, static, null, null, var, var, Instance of 'NoType', x5, DeclarationKind.Class)
+ listener: handleNoType(var)
+ ensureIdentifier(var, fieldDeclaration)
+ listener: handleIdentifier(x5, fieldDeclaration)
+ parseFieldInitializerOpt(x5, x5, null, var, DeclarationKind.Class)
+ listener: beginFieldInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseLiteralInt(=)
+ listener: handleLiteralInt(0)
+ listener: endFieldInitializer(=, ;)
+ listener: endClassFields(static, null, null, var, 1, static, ;)
+ listener: endMember()
+ notEofOrValue(}, covariant)
+ parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, X)
+ parseMetadataStar(;)
+ listener: beginMetadataStar(covariant)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseFields(;, null, null, covariant, null, var, var, Instance of 'NoType', x6, DeclarationKind.Class)
+ listener: handleNoType(var)
+ ensureIdentifier(var, fieldDeclaration)
+ listener: handleIdentifier(x6, fieldDeclaration)
+ parseFieldInitializerOpt(x6, x6, null, var, DeclarationKind.Class)
+ listener: beginFieldInitializer(=)
+ parseExpression(=)
+ parsePrecedenceExpression(=, 1, true)
+ parseUnaryExpression(=, true)
+ parsePrimary(=, expression)
+ parseLiteralInt(=)
+ listener: handleLiteralInt(0)
+ listener: endFieldInitializer(=, ;)
+ listener: endClassFields(null, covariant, null, var, 1, covariant, ;)
+ listener: endMember()
+ notEofOrValue(}, })
+ listener: endClassOrMixinBody(DeclarationKind.Class, 6, {, })
+ listener: endClassDeclaration(class, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(class)
+ listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.parser.expect
new file mode 100644
index 0000000..e774ae5
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.parser.expect
@@ -0,0 +1,19 @@
+class X {
+var x1;
+static var x2;
+covariant var x3;
+var x4 = 0;
+static var x5 = 0;
+covariant var x6 = 0;
+}
+
+
+class[KeywordToken] X[StringToken] {[BeginToken]
+var[KeywordToken] x1[StringToken];[SimpleToken]
+static[KeywordToken] var[KeywordToken] x2[StringToken];[SimpleToken]
+covariant[KeywordToken] var[KeywordToken] x3[StringToken];[SimpleToken]
+var[KeywordToken] x4[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+static[KeywordToken] var[KeywordToken] x5[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+covariant[KeywordToken] var[KeywordToken] x6[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.scanner.expect
new file mode 100644
index 0000000..e774ae5
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_39858_prime1.dart.scanner.expect
@@ -0,0 +1,19 @@
+class X {
+var x1;
+static var x2;
+covariant var x3;
+var x4 = 0;
+static var x5 = 0;
+covariant var x6 = 0;
+}
+
+
+class[KeywordToken] X[StringToken] {[BeginToken]
+var[KeywordToken] x1[StringToken];[SimpleToken]
+static[KeywordToken] var[KeywordToken] x2[StringToken];[SimpleToken]
+covariant[KeywordToken] var[KeywordToken] x3[StringToken];[SimpleToken]
+var[KeywordToken] x4[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+static[KeywordToken] var[KeywordToken] x5[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+covariant[KeywordToken] var[KeywordToken] x6[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart
new file mode 100644
index 0000000..439fe5f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart
@@ -0,0 +1,23 @@
+// 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.
+
+void foo({required String s}) {}
+void Function({required String s}) g;
+
+class A {
+ A({required int x});
+ foo({required int y}) {}
+ void Function({required String s}) f;
+}
+
+bar() {
+ foo();
+ new A();
+ var a = new A(x: 42);
+ a.foo();
+ a.f();
+ g();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.outline.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.outline.expect
new file mode 100644
index 0000000..18f2365
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.outline.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field ({required s: core::String}) → void f;
+ constructor •({required core::int x}) → self::A
+ ;
+ method foo({required core::int y}) → dynamic
+ ;
+}
+static field ({required s: core::String}) → void g;
+static method foo({required core::String s}) → void
+ ;
+static method bar() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.expect
new file mode 100644
index 0000000..f8923db
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.expect
@@ -0,0 +1,59 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Error: Required named parameter 's' must be provided.
+// foo();
+// ^
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:5:6: Context: Found this candidate, but the arguments don't match.
+// void foo({required String s}) {}
+// ^^^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:16:8: Error: Required named parameter 'x' must be provided.
+// new A();
+// ^
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:9:3: Context: Found this candidate, but the arguments don't match.
+// A({required int x});
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:18:8: Error: Required named parameter 'y' must be provided.
+// a.foo();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:19:6: Error: Required named parameter 's' must be provided.
+// a.f();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:20:4: Error: Required named parameter 's' must be provided.
+// g();
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field ({required s: core::String}) → void f = null;
+ constructor •({required core::int x = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ method foo({required core::int y = #C1}) → dynamic {}
+}
+static field ({required s: core::String}) → void g;
+static method foo({required core::String s = #C1}) → void {}
+static method bar() → dynamic {
+ invalid-expression "pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Error: Required named parameter 's' must be provided.
+ foo();
+ ^";
+ invalid-expression "pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:16:8: Error: Required named parameter 'x' must be provided.
+ new A();
+ ^";
+ self::A a = new self::A::•(x: 42);
+ a.{self::A::foo}();
+ a.{self::A::f}();
+ self::g.call();
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.transformed.expect
new file mode 100644
index 0000000..f8923db
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.transformed.expect
@@ -0,0 +1,59 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Error: Required named parameter 's' must be provided.
+// foo();
+// ^
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:5:6: Context: Found this candidate, but the arguments don't match.
+// void foo({required String s}) {}
+// ^^^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:16:8: Error: Required named parameter 'x' must be provided.
+// new A();
+// ^
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:9:3: Context: Found this candidate, but the arguments don't match.
+// A({required int x});
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:18:8: Error: Required named parameter 'y' must be provided.
+// a.foo();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:19:6: Error: Required named parameter 's' must be provided.
+// a.f();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:20:4: Error: Required named parameter 's' must be provided.
+// g();
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field ({required s: core::String}) → void f = null;
+ constructor •({required core::int x = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ method foo({required core::int y = #C1}) → dynamic {}
+}
+static field ({required s: core::String}) → void g;
+static method foo({required core::String s = #C1}) → void {}
+static method bar() → dynamic {
+ invalid-expression "pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Error: Required named parameter 's' must be provided.
+ foo();
+ ^";
+ invalid-expression "pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:16:8: Error: Required named parameter 'x' must be provided.
+ new A();
+ ^";
+ self::A a = new self::A::•(x: 42);
+ a.{self::A::foo}();
+ a.{self::A::f}();
+ self::g.call();
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.expect
new file mode 100644
index 0000000..b6243a6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.expect
@@ -0,0 +1,49 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Warning: Missing required named parameter 's'.
+// foo();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:16:8: Warning: Missing required named parameter 'x'.
+// new A();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:18:8: Warning: Missing required named parameter 'y'.
+// a.foo();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:19:6: Warning: Missing required named parameter 's'.
+// a.f();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:20:4: Warning: Missing required named parameter 's'.
+// g();
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field ({required s: core::String}) → void f = null;
+ constructor •({required core::int x = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ method foo({required core::int y = #C1}) → dynamic {}
+}
+static field ({required s: core::String}) → void g;
+static method foo({required core::String s = #C1}) → void {}
+static method bar() → dynamic {
+ self::foo();
+ new self::A::•();
+ self::A a = new self::A::•(x: 42);
+ a.{self::A::foo}();
+ a.{self::A::f}();
+ self::g.call();
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.transformed.expect
new file mode 100644
index 0000000..b6243a6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.transformed.expect
@@ -0,0 +1,49 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Warning: Missing required named parameter 's'.
+// foo();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:16:8: Warning: Missing required named parameter 'x'.
+// new A();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:18:8: Warning: Missing required named parameter 'y'.
+// a.foo();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:19:6: Warning: Missing required named parameter 's'.
+// a.f();
+// ^
+//
+// pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:20:4: Warning: Missing required named parameter 's'.
+// g();
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field ({required s: core::String}) → void f = null;
+ constructor •({required core::int x = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ method foo({required core::int y = #C1}) → dynamic {}
+}
+static field ({required s: core::String}) → void g;
+static method foo({required core::String s = #C1}) → void {}
+static method bar() → dynamic {
+ self::foo();
+ new self::A::•();
+ self::A a = new self::A::•(x: 42);
+ a.{self::A::foo}();
+ a.{self::A::f}();
+ self::g.call();
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index eca92fb..d96b9d1 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -940,6 +940,7 @@
nnbd/late: TextSerializationFailure
nnbd/messages_with_types_opt_in: TypeCheckError
nnbd/messages_with_types_opt_out: TypeCheckError
+nnbd/missing_required_named_parameter: TextSerializationFailure
nnbd/no_null_shorting: TextSerializationFailure
nnbd/no_null_shorting_explicit_extension: TextSerializationFailure
nnbd/no_null_shorting_extension: TextSerializationFailure
diff --git a/pkg/front_end/tool/perf.dart b/pkg/front_end/tool/perf.dart
index 6c82961..2c6fd5b 100644
--- a/pkg/front_end/tool/perf.dart
+++ b/pkg/front_end/tool/perf.dart
@@ -198,8 +198,8 @@
/// sources.
Future setup(Uri entryUri) async {
var provider = PhysicalResourceProvider.INSTANCE;
- var packageMap = new ContextBuilder(provider, null, null)
- .convertPackagesToMap(await findPackages(entryUri));
+ var packageMap = ContextBuilder.convertPackagesToMap(
+ provider, await findPackages(entryUri));
sources = new SourceFactory([
new ResourceUriResolver(provider),
new PackageMapUriResolver(provider, packageMap),
diff --git a/pkg/nnbd_migration/lib/instrumentation.dart b/pkg/nnbd_migration/lib/instrumentation.dart
index 5afa1c3..dd0a250 100644
--- a/pkg/nnbd_migration/lib/instrumentation.dart
+++ b/pkg/nnbd_migration/lib/instrumentation.dart
@@ -143,6 +143,7 @@
isCheckComponentType,
isCheckMainType,
literal,
+ listLengthConstructor,
namedParameterNotSupplied,
nonNullableBoolType,
nonNullableObjectSuperclass,
diff --git a/pkg/nnbd_migration/lib/nnbd_migration.dart b/pkg/nnbd_migration/lib/nnbd_migration.dart
index 019900d..0e7e047 100644
--- a/pkg/nnbd_migration/lib/nnbd_migration.dart
+++ b/pkg/nnbd_migration/lib/nnbd_migration.dart
@@ -95,10 +95,14 @@
/// [FixBuilder] infrastructure. Once FixBuilder is at feature parity with
/// the old implementation, this option will be removed and FixBuilder will
/// be used unconditionally.
+ ///
+ /// Optional parameter [removeViaComments] indicates whether dead code should
+ /// be removed in its entirety (the default) or removed by commenting it out.
factory NullabilityMigration(NullabilityMigrationListener listener,
{bool permissive,
NullabilityMigrationInstrumentation instrumentation,
- bool useFixBuilder}) = NullabilityMigrationImpl;
+ bool useFixBuilder,
+ bool removeViaComments}) = NullabilityMigrationImpl;
void finalizeInput(ResolvedUnitResult result);
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 4940535..d9e823d 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -883,6 +883,14 @@
decoratedTypeArguments = const [];
}
}
+
+ if (node.staticType.isDartCoreList &&
+ callee.name == '' &&
+ node.argumentList.arguments.length == 1) {
+ _graph.connect(_graph.always, decoratedTypeArguments[0].node,
+ ListLengthConstructorOrigin(source, node));
+ }
+
var nullabilityNode = NullabilityNode.forInferredType();
_graph.makeNonNullable(
nullabilityNode, InstanceCreationOrigin(source, node));
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 40feb43..5f9eb0a 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -238,6 +238,16 @@
EdgeOriginKind get kind => EdgeOriginKind.isCheckMainType;
}
+/// An edge origin used for the type argument of a list constructor that
+/// specified an initial length, because that type argument must be nullable.
+class ListLengthConstructorOrigin extends EdgeOrigin {
+ ListLengthConstructorOrigin(Source source, AstNode node)
+ : super(source, node);
+
+ @override
+ EdgeOriginKind get kind => EdgeOriginKind.listLengthConstructor;
+}
+
/// An edge origin used for edges that originated because a literal expression
/// has a known nullability.
class LiteralOrigin extends EdgeOrigin {
diff --git a/pkg/nnbd_migration/lib/src/edit_plan.dart b/pkg/nnbd_migration/lib/src/edit_plan.dart
index 75aa12b..e93001c 100644
--- a/pkg/nnbd_migration/lib/src/edit_plan.dart
+++ b/pkg/nnbd_migration/lib/src/edit_plan.dart
@@ -10,9 +10,9 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:meta/meta.dart';
-/// Abstract base class representing a single atomic change to a source file,
-/// decoupled from the location at which the change is made. The [EditPlan]
-/// class performs its duties by creating and manipulating [AtomicEdit] objects.
+/// A single atomic change to a source file, decoupled from the location at
+/// which the change is made. The [EditPlan] class performs its duties by
+/// creating and manipulating [AtomicEdit] objects.
///
/// A list of [AtomicEdit]s may be converted to a [SourceEdit] using the
/// extension [AtomicEditList], and a map of offsets to lists of [AtomicEdit]s
@@ -20,34 +20,50 @@
/// [AtomicEditMap].
///
/// May be subclassed to allow additional information to be recorded about the
-/// deletion.
-abstract class AtomicEdit {
- const AtomicEdit();
-
- /// Queries the number of source characters that should be deleted by this
- /// edit, or 0 if no characters should be deleted.
- int get length;
-
- /// Queries the source characters that should be inserted by this edit, or
- /// the empty string if no characters should be inserted.
- String get replacement;
-}
-
-/// Implementation of [AtomicEdit] that deletes characters of text.
-///
-/// May be subclassed to allow additional information to be recorded about the
-/// deletion.
-class DeleteText extends AtomicEdit {
- @override
+/// edit.
+class AtomicEdit {
+ /// The number of characters that should be deleted by this edit, or `0` if no
+ /// characters should be deleted.
final int length;
- const DeleteText(this.length);
+ /// The characters that should be inserted by this edit, or the empty string
+ /// if no characters should be inserted.
+ final String replacement;
+
+ /// Initialize an edit to delete [length] characters.
+ const AtomicEdit.delete(this.length)
+ : assert(length > 0),
+ replacement = '';
+
+ /// Initialize an edit to insert the [replacement] characters.
+ const AtomicEdit.insert(this.replacement)
+ : assert(replacement.length > 0),
+ length = 0;
+
+ /// Initialize an edit to replace [length] characters with the [replacement]
+ /// characters.
+ const AtomicEdit.replace(this.length, this.replacement)
+ : assert(length > 0 || replacement.length > 0);
+
+ /// Return `true` if this edit is a deletion (no characters added).
+ bool get isDeletion => replacement.length == 0;
+
+ /// Return `true` if this edit is an insertion (no characters removed).
+ bool get isInsertion => length == 0;
+
+ /// Return `true` if this edit is a replacement.
+ bool get isReplacement => length > 0 && replacement.length > 0;
@override
- String get replacement => '';
-
- @override
- String toString() => 'DeleteText($length)';
+ String toString() {
+ if (isInsertion) {
+ return 'InsertText(${json.encode(replacement)})';
+ } else if (isDeletion) {
+ return 'DeleteText($length)';
+ } else {
+ return 'ReplaceText($length, ${json.encode(replacement)})';
+ }
+ }
}
/// An [EditPlan] is a builder capable of accumulating a set of edits to be
@@ -65,89 +81,27 @@
/// [EditPlan.finalize] to convert into a representation of the concrete edits
/// that need to be made to the source file.
abstract class EditPlan {
- /// The AST node to which the edit plan applies.
- final AstNode sourceNode;
+ EditPlan._();
- EditPlan._(this.sourceNode);
+ /// Returns the "parent" of the node edited by this [EditPlan]. For edit
+ /// plans that replace one AST node with another, this is the parent of the
+ /// AST node being replaced. For edit plans that insert or delete AST nodes,
+ /// this is the parent of the AST nodes that will be inserted or deleted.
+ AstNode get parentNode;
- /// If the result of executing this [EditPlan] will be an expression,
- /// indicates whether the expression will end in an unparenthesized cascade.
- @visibleForTesting
- bool get endsInCascade;
-
- /// Converts this [EditPlan] a representation of the concrete edits that need
- /// to be made to the source file. These edits may be converted into
- /// [SourceEdit]s using the extensions [AtomicEditList] and [AtomicEditMap].
+ /// Returns a new [EditPlan] that replicates this [EditPlan], but may
+ /// incorporate relevant information obtained from the parent of [sourceNode].
+ /// For example, if this [EditPlan] would produce an expression that might or
+ /// might not need parentheses, and the parent of [sourceNode] is a
+ /// [ParenthesizedExpression], then an [EditPlan] is produced that will either
+ /// preserve the existing parentheses, or remove them, as appropriate.
///
- /// Finalizing an [EditPlan] is a destructive operation; it should not be used
- /// again after it is finalized.
- Map<int, List<AtomicEdit>> finalize() {
- var plan = _incorporateParenParentIfPresent(null);
- return plan._getChanges(plan.parensNeededFromContext(null));
- }
-
- /// Determines whether the text produced by this [EditPlan] would need
- /// parentheses if it were to be used as a replacement for its [sourceNode].
- ///
- /// If this [EditPlan] would produce an expression that ends in a cascade, it
- /// will be necessary to search the [sourceNode]'s ancestors to see if any of
- /// them represents a cascade section (and hence, parentheses are required).
- /// If a non-null value is provided for [cascadeSearchLimit], it is the most
- /// distant ancestor that will be searched.
- @visibleForTesting
- bool parensNeededFromContext(AstNode cascadeSearchLimit) {
- if (sourceNode is! Expression) return false;
- var parent = sourceNode.parent;
- return parent == null
- ? false
- : parent
- .accept(_ParensNeededFromContextVisitor(this, cascadeSearchLimit));
- }
-
- /// Modifies [changes] to insert parentheses enclosing the [sourceNode]. This
- /// works even if [changes] already includes modifications at the beginning or
- /// end of [sourceNode]--the parentheses are inserted outside of any
- /// pre-existing changes.
- Map<int, List<AtomicEdit>> _createAddParenChanges(
- Map<int, List<AtomicEdit>> changes) {
- changes ??= {};
- (changes[sourceNode.offset] ??= []).insert(0, const InsertText('('));
- (changes[sourceNode.end] ??= []).add(const InsertText(')'));
- return changes;
- }
-
- /// Computes the necessary set of [changes] for this [EditPlan], either
- /// including or not including parentheses depending on the value of [parens].
- ///
- /// An [EditPlan] for which [_getChanges] has been called is considered to be
- /// finalized.
- Map<int, List<AtomicEdit>> _getChanges(bool parens);
-
- /// If the [sourceNode]'s parent is a [ParenthesizedExpression] returns a
- /// [_ProvisionalParenEditPlan] which will keep or discard the enclosing
- /// parentheses as necessary based on precedence. Otherwise, returns this.
- ///
- /// If [limit] is provided, and it is the same as [sourceNode]'s parent, then
- /// the parent is ignored. This is used to avoid trying to remove parentheses
- /// twice.
+ /// May return `this`, if no information needs to be incorporated from the
+ /// parent.
///
/// This method is used when composing and finalizing plans, to ensure that
/// parentheses are removed when they are no longer needed.
- EditPlan _incorporateParenParentIfPresent(AstNode limit) {
- var parent = sourceNode.parent;
- if (!identical(parent, limit) && parent is ParenthesizedExpression) {
- return _ProvisionalParenEditPlan(parent, this);
- } else {
- return this;
- }
- }
-
- /// Determines if the text that would be produced by [EditPlan] needs to be
- /// surrounded by parens, based on the context in which it will be used.
- bool _parensNeeded(
- {@required Precedence threshold,
- bool associative = false,
- bool allowCascade = false});
+ NodeProducingEditPlan _incorporateParent();
}
/// Factory class for creating [EditPlan]s.
@@ -170,18 +124,33 @@
/// [innerPlan] will be finalized as a side effect (either immediately or when
/// the newly created plan is finalized), so it should not be re-used by the
/// caller.
- EditPlan extract(AstNode sourceNode, EditPlan innerPlan) {
- innerPlan = innerPlan._incorporateParenParentIfPresent(sourceNode);
+ NodeProducingEditPlan extract(
+ AstNode sourceNode, NodeProducingEditPlan innerPlan) {
+ if (!identical(innerPlan.sourceNode.parent, sourceNode)) {
+ innerPlan = innerPlan._incorporateParent();
+ }
return _ExtractEditPlan(sourceNode, innerPlan, this);
}
+ /// Converts [plan] to a representation of the concrete edits that need
+ /// to be made to the source file. These edits may be converted into
+ /// [SourceEdit]s using the extensions [AtomicEditList] and [AtomicEditMap].
+ ///
+ /// Finalizing an [EditPlan] is a destructive operation; it should not be used
+ /// again after it is finalized.
+ Map<int, List<AtomicEdit>> finalize(EditPlan plan) {
+ var incorporatedPlan = plan._incorporateParent();
+ return incorporatedPlan
+ ._getChanges(incorporatedPlan.parensNeededFromContext(null));
+ }
+
/// Creates a new edit plan that makes no changes to [node], but may make
/// changes to some of its descendants (specified via [innerPlans]).
///
/// All plans in [innerPlans] will be finalized as a side effect (either
/// immediately or when the newly created plan is finalized), so they should
/// not be re-used by the caller.
- EditPlan passThrough(AstNode node,
+ NodeProducingEditPlan passThrough(AstNode node,
{Iterable<EditPlan> innerPlans = const []}) {
if (node is ParenthesizedExpression) {
return _ProvisionalParenEditPlan(
@@ -213,9 +182,9 @@
/// Note that [endsInCascade] is ignored if there is no [suffix] (since in
/// this situation, whether the final plan ends in a cascade section will be
/// determined by [innerPlan]).
- EditPlan surround(EditPlan innerPlan,
- {List<InsertText> prefix,
- List<InsertText> suffix,
+ NodeProducingEditPlan surround(NodeProducingEditPlan innerPlan,
+ {List<AtomicEdit> prefix,
+ List<AtomicEdit> suffix,
Precedence outerPrecedence = Precedence.primary,
Precedence innerPrecedence = Precedence.none,
bool associative = false,
@@ -243,21 +212,76 @@
}
}
-/// Implementation of [AtomicEdit] that inserts a string of new text.
-///
-/// May be subclassed to allow additional information to be recorded about the
-/// insertion.
-class InsertText extends AtomicEdit {
- @override
- final String replacement;
+/// Specialization of [EditPlan] for the situation where the text being produced
+/// represents a single expression (i.e. an expression, statement, class
+/// declaration, etc.)
+abstract class NodeProducingEditPlan extends EditPlan {
+ /// The AST node to which the edit plan applies.
+ final AstNode sourceNode;
- const InsertText(this.replacement);
+ NodeProducingEditPlan._(this.sourceNode) : super._();
+
+ /// If the result of executing this [EditPlan] will be an expression,
+ /// indicates whether the expression will end in an unparenthesized cascade.
+ @visibleForTesting
+ bool get endsInCascade;
@override
- int get length => 0;
+ AstNode get parentNode => sourceNode.parent;
+
+ /// Determines whether the text produced by this [EditPlan] would need
+ /// parentheses if it were to be used as a replacement for its [sourceNode].
+ ///
+ /// If this [EditPlan] would produce an expression that ends in a cascade, it
+ /// will be necessary to search the [sourceNode]'s ancestors to see if any of
+ /// them represents a cascade section (and hence, parentheses are required).
+ /// If a non-null value is provided for [cascadeSearchLimit], it is the most
+ /// distant ancestor that will be searched.
+ @visibleForTesting
+ bool parensNeededFromContext(AstNode cascadeSearchLimit) {
+ if (sourceNode is! Expression) return false;
+ var parent = sourceNode.parent;
+ return parent == null
+ ? false
+ : parent
+ .accept(_ParensNeededFromContextVisitor(this, cascadeSearchLimit));
+ }
+
+ /// Modifies [changes] to insert parentheses enclosing the [sourceNode]. This
+ /// works even if [changes] already includes modifications at the beginning or
+ /// end of [sourceNode]--the parentheses are inserted outside of any
+ /// pre-existing changes.
+ Map<int, List<AtomicEdit>> _createAddParenChanges(
+ Map<int, List<AtomicEdit>> changes) {
+ changes ??= {};
+ (changes[sourceNode.offset] ??= []).insert(0, const AtomicEdit.insert('('));
+ (changes[sourceNode.end] ??= []).add(const AtomicEdit.insert(')'));
+ return changes;
+ }
+
+ /// Computes the necessary set of [changes] for this [EditPlan], either
+ /// including or not including parentheses depending on the value of [parens].
+ ///
+ /// An [EditPlan] for which [_getChanges] has been called is considered to be
+ /// finalized.
+ Map<int, List<AtomicEdit>> _getChanges(bool parens);
@override
- String toString() => 'InsertText(${json.encode(replacement)})';
+ NodeProducingEditPlan _incorporateParent() {
+ var parent = sourceNode.parent;
+ if (parent is ParenthesizedExpression) {
+ return _ProvisionalParenEditPlan(parent, this);
+ } else {
+ return this;
+ }
+ }
+
+ /// Determines if the text that would be produced by [EditPlan] needs to be
+ /// surrounded by parens, based on the context in which it will be used.
+ bool _parensNeeded(
+ {@required Precedence threshold,
+ bool associative = false,
+ bool allowCascade = false});
}
/// Visitor that determines whether a given [AstNode] ends in a cascade.
@@ -288,7 +312,8 @@
class _ExtractEditPlan extends _NestedEditPlan {
final EditPlanner _planner;
- _ExtractEditPlan(AstNode sourceNode, EditPlan innerPlan, this._planner)
+ _ExtractEditPlan(
+ AstNode sourceNode, NodeProducingEditPlan innerPlan, this._planner)
: super(sourceNode, innerPlan);
@override
@@ -326,17 +351,17 @@
switch (removalStyle) {
case _RemovalStyle.commentSpace:
return {
- offset: [InsertText('/* ')],
- end: [InsertText('*/ ')]
+ offset: [AtomicEdit.insert('/* ')],
+ end: [AtomicEdit.insert('*/ ')]
};
case _RemovalStyle.delete:
return {
- offset: [DeleteText(end - offset)]
+ offset: [AtomicEdit.delete(end - offset)]
};
case _RemovalStyle.spaceComment:
return {
- offset: [InsertText(' /*')],
- end: [InsertText(' */')]
+ offset: [AtomicEdit.insert(' /*')],
+ end: [AtomicEdit.insert(' */')]
};
}
throw StateError('Null value for removalStyle');
@@ -351,8 +376,8 @@
///
/// By default, defers computation of whether parentheses are needed to the
/// inner plan.
-abstract class _NestedEditPlan extends EditPlan {
- final EditPlan innerPlan;
+abstract class _NestedEditPlan extends NodeProducingEditPlan {
+ final NodeProducingEditPlan innerPlan;
_NestedEditPlan(AstNode sourceNode, this.innerPlan) : super._(sourceNode);
@@ -374,7 +399,7 @@
/// based on the context surrounding its source node. To use this class, visit
/// the source node's parent.
class _ParensNeededFromContextVisitor extends GeneralizingAstVisitor<bool> {
- final EditPlan _editPlan;
+ final NodeProducingEditPlan _editPlan;
/// If [_editPlan] would produce an expression that ends in a cascade, it
/// will be necessary to search the [_target]'s ancestors to see if any of
@@ -590,19 +615,26 @@
bool /*?*/ endsInCascade = node is CascadeExpression ? true : null;
Map<int, List<AtomicEdit>> changes;
for (var innerPlan in innerPlans) {
- innerPlan = innerPlan._incorporateParenParentIfPresent(node);
- var parensNeeded = innerPlan.parensNeededFromContext(node);
- assert(_checkParenLogic(innerPlan, parensNeeded));
- if (!parensNeeded && innerPlan is _ProvisionalParenEditPlan) {
- var innerInnerPlan = innerPlan.innerPlan;
- if (innerInnerPlan is _PassThroughEditPlan) {
- // Input source code had redundant parens, so keep them.
- parensNeeded = true;
- }
+ if (!identical(innerPlan.parentNode, node)) {
+ innerPlan = innerPlan._incorporateParent();
}
- changes += innerPlan._getChanges(parensNeeded);
- if (endsInCascade == null && innerPlan.sourceNode.end == node.end) {
- endsInCascade = !parensNeeded && innerPlan.endsInCascade;
+ if (innerPlan is NodeProducingEditPlan) {
+ var parensNeeded = innerPlan.parensNeededFromContext(node);
+ assert(_checkParenLogic(innerPlan, parensNeeded));
+ if (!parensNeeded && innerPlan is _ProvisionalParenEditPlan) {
+ var innerInnerPlan = innerPlan.innerPlan;
+ if (innerInnerPlan is _PassThroughEditPlan) {
+ // Input source code had redundant parens, so keep them.
+ parensNeeded = true;
+ }
+ }
+ changes += innerPlan._getChanges(parensNeeded);
+ if (endsInCascade == null && innerPlan.sourceNode.end == node.end) {
+ endsInCascade = !parensNeeded && innerPlan.endsInCascade;
+ }
+ } else {
+ // TODO(paulberry): handle this case.
+ throw UnimplementedError('Inner plan is not node-producing');
}
}
return _PassThroughEditPlan._(
@@ -640,7 +672,8 @@
/// Caller should not re-use [innerPlan] after this call--it (and the data
/// structures it points to) may be incorporated into this edit plan and later
/// modified.
- _ProvisionalParenEditPlan(ParenthesizedExpression node, EditPlan innerPlan)
+ _ProvisionalParenEditPlan(
+ ParenthesizedExpression node, NodeProducingEditPlan innerPlan)
: super(node, innerPlan);
@override
@@ -648,8 +681,8 @@
var changes = innerPlan._getChanges(false);
if (!parens) {
changes ??= {};
- (changes[sourceNode.offset] ??= []).insert(0, const DeleteText(1));
- (changes[sourceNode.end - 1] ??= []).add(const DeleteText(1));
+ (changes[sourceNode.offset] ??= []).insert(0, const AtomicEdit.delete(1));
+ (changes[sourceNode.end - 1] ??= []).add(const AtomicEdit.delete(1));
}
return changes;
}
@@ -672,7 +705,7 @@
/// Implementation of [EditPlan] underlying simple cases where no computation
/// needs to be deferred.
-class _SimpleEditPlan extends EditPlan {
+class _SimpleEditPlan extends NodeProducingEditPlan {
final Precedence _precedence;
@override
diff --git a/pkg/nnbd_migration/lib/src/fix_aggregator.dart b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
index 67174a4..ffdd042 100644
--- a/pkg/nnbd_migration/lib/src/fix_aggregator.dart
+++ b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
@@ -13,14 +13,15 @@
/// TODO(paulberry): store additional information necessary to include in the
/// preview.
class AddRequiredKeyword extends _NestableChange {
- const AddRequiredKeyword([NodeChange inner = const NoChange()])
+ const AddRequiredKeyword(
+ [NodeChange<NodeProducingEditPlan> inner = const NoChange()])
: super(inner);
@override
EditPlan apply(AstNode node, FixAggregator aggregator) {
var innerPlan = _inner.apply(node, aggregator);
return aggregator.planner
- .surround(innerPlan, prefix: [const InsertText('required ')]);
+ .surround(innerPlan, prefix: [const AtomicEdit.insert('required ')]);
}
}
@@ -40,7 +41,7 @@
/// Gathers all the changes to nodes descended from [node] into a single
/// [EditPlan].
- EditPlan innerPlanForNode(AstNode node) {
+ NodeProducingEditPlan innerPlanForNode(AstNode node) {
var previousPlans = _plans;
try {
_plans = [];
@@ -77,7 +78,7 @@
} else {
plan = planner.passThrough(unit, innerPlans: aggregator._plans);
}
- return plan.finalize();
+ return planner.finalize(plan);
}
}
@@ -90,14 +91,15 @@
/// TODO(paulberry): shouldn't be a String
final String type;
- const IntroduceAs(this.type, [NodeChange inner = const NoChange()])
+ const IntroduceAs(this.type,
+ [NodeChange<NodeProducingEditPlan> inner = const NoChange()])
: super(inner);
@override
EditPlan apply(AstNode node, FixAggregator aggregator) {
var innerPlan = _inner.apply(node, aggregator);
return aggregator.planner.surround(innerPlan,
- suffix: [InsertText(' as $type')],
+ suffix: [AtomicEdit.insert(' as $type')],
outerPrecedence: Precedence.relational,
innerPrecedence: Precedence.relational);
}
@@ -109,31 +111,33 @@
/// TODO(paulberry): store additional information necessary to include in the
/// preview.
class MakeNullable extends _NestableChange {
- const MakeNullable([NodeChange inner = const NoChange()]) : super(inner);
+ const MakeNullable(
+ [NodeChange<NodeProducingEditPlan> inner = const NoChange()])
+ : super(inner);
@override
EditPlan apply(AstNode node, FixAggregator aggregator) {
var innerPlan = _inner.apply(node, aggregator);
return aggregator.planner
- .surround(innerPlan, suffix: [const InsertText('?')]);
+ .surround(innerPlan, suffix: [const AtomicEdit.insert('?')]);
}
}
/// Implementation of [NodeChange] representing no change at all. This class
/// is intended to be used as a base class for changes that wrap around other
/// changes.
-class NoChange extends NodeChange {
+class NoChange extends NodeChange<NodeProducingEditPlan> {
const NoChange();
@override
- EditPlan apply(AstNode node, FixAggregator aggregator) {
+ NodeProducingEditPlan apply(AstNode node, FixAggregator aggregator) {
return aggregator.innerPlanForNode(node);
}
}
/// Base class representing a kind of change that [FixAggregator] might make to a
/// particular AST node.
-abstract class NodeChange {
+abstract class NodeChange<P extends EditPlan> {
const NodeChange();
/// Applies this change to the given [node], producing an [EditPlan]. The
@@ -145,7 +149,7 @@
/// below them (e.g. dropping an unnecessary cast), so those changes need to
/// be able to call the appropriate [aggregator] methods just on the nodes
/// they need.
- EditPlan apply(AstNode node, FixAggregator aggregator);
+ P apply(AstNode node, FixAggregator aggregator);
}
/// Implementation of [NodeChange] representing the addition of a null check to
@@ -154,13 +158,14 @@
/// TODO(paulberry): store additional information necessary to include in the
/// preview.
class NullCheck extends _NestableChange {
- const NullCheck([NodeChange inner = const NoChange()]) : super(inner);
+ const NullCheck([NodeChange<NodeProducingEditPlan> inner = const NoChange()])
+ : super(inner);
@override
EditPlan apply(AstNode node, FixAggregator aggregator) {
var innerPlan = _inner.apply(node, aggregator);
return aggregator.planner.surround(innerPlan,
- suffix: [const InsertText('!')],
+ suffix: [const AtomicEdit.insert('!')],
outerPrecedence: Precedence.postfix,
innerPrecedence: Precedence.postfix,
associative: true);
@@ -173,7 +178,8 @@
/// TODO(paulberry): store additional information necessary to include in the
/// preview.
class RemoveAs extends _NestableChange {
- const RemoveAs([NodeChange inner = const NoChange()]) : super(inner);
+ const RemoveAs([NodeChange<NodeProducingEditPlan> inner = const NoChange()])
+ : super(inner);
@override
EditPlan apply(AstNode node, FixAggregator aggregator) {
@@ -184,7 +190,7 @@
/// Shared base class for [NodeChange]s that are based on an [_inner] change.
abstract class _NestableChange extends NodeChange {
- final NodeChange _inner;
+ final NodeChange<NodeProducingEditPlan> _inner;
const _NestableChange(this._inner);
}
diff --git a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
index 13653e7..cff8c09 100644
--- a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
@@ -54,10 +54,15 @@
/// [FixBuilder] infrastructure. Once FixBuilder is at feature parity with
/// the old implementation, this option will be removed and FixBuilder will
/// be used unconditionally.
+ ///
+ /// Optional parameter [removeViaComments] indicates whether dead code should
+ /// be removed in its entirety (the default) or removed by commenting it out.
+ /// TODO(paulberry): wire this up.
NullabilityMigrationImpl(NullabilityMigrationListener listener,
{bool permissive: false,
NullabilityMigrationInstrumentation instrumentation,
- bool useFixBuilder: false})
+ bool useFixBuilder: false,
+ bool removeViaComments = false})
: this._(listener, NullabilityGraph(instrumentation: instrumentation),
permissive, instrumentation, useFixBuilder);
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 7c88bbf..8aaf324 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -41,14 +41,20 @@
/// Verifies that migration of the files in [input] produces the output in
/// [expectedOutput].
+ ///
+ /// Optional parameter [removeViaComments] indicates whether dead code should
+ /// be removed in its entirety (the default) or removed by commenting it out.
Future<void> _checkMultipleFileChanges(
- Map<String, String> input, Map<String, String> expectedOutput) async {
+ Map<String, String> input, Map<String, String> expectedOutput,
+ {bool removeViaComments = false}) async {
for (var path in input.keys) {
driver.getFileSync(newFile(path, content: input[path]).path);
}
var listener = new TestMigrationListener();
var migration = NullabilityMigration(listener,
- permissive: _usePermissiveMode, useFixBuilder: _useFixBuilder);
+ permissive: _usePermissiveMode,
+ useFixBuilder: _useFixBuilder,
+ removeViaComments: removeViaComments);
for (var path in input.keys) {
migration.prepareInput(await session.getResolvedUnit(path));
}
@@ -77,10 +83,15 @@
/// Verifies that migraiton of the single file with the given [content]
/// produces the [expected] output.
- Future<void> _checkSingleFileChanges(String content, String expected) async {
+ ///
+ /// Optional parameter [removeViaComments] indicates whether dead code should
+ /// be removed in its entirety (the default) or removed by commenting it out.
+ Future<void> _checkSingleFileChanges(String content, String expected,
+ {bool removeViaComments = false}) async {
var sourcePath = convertPath('/home/test/lib/test.dart');
await _checkMultipleFileChanges(
- {sourcePath: content}, {sourcePath: expected});
+ {sourcePath: content}, {sourcePath: expected},
+ removeViaComments: removeViaComments);
}
}
@@ -993,7 +1004,7 @@
} */
}
''';
- await _checkSingleFileChanges(content, expected);
+ await _checkSingleFileChanges(content, expected, removeViaComments: true);
}
Future<void> test_downcast_dynamic_function_to_functionType() async {
@@ -3129,7 +3140,7 @@
f(1, null, null);
}
''';
- await _checkSingleFileChanges(content, expected);
+ await _checkSingleFileChanges(content, expected, removeViaComments: true);
}
Future<void> test_prefix_minus() async {
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 58d5387..a63a9a3 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -3401,6 +3401,30 @@
// Passes if no exceptions are thrown.
}
+ Future<void> test_list_constructor_length() async {
+ await analyze('''
+void main() {
+ List<int/*1*/> list = List<int/*2*/>(10);
+}
+''');
+ final variableParam = decoratedTypeAnnotation('int/*1*/');
+ final filledParam = decoratedTypeAnnotation('int/*2*/');
+
+ assertEdge(filledParam.node, variableParam.node, hard: false);
+ assertEdge(always, filledParam.node, hard: false);
+ }
+
+ Future<void> test_list_constructor_length_implicitParam() async {
+ await analyze('''
+void main() {
+ List<int/*1*/> list = List(10);
+}
+''');
+ final variableParam = decoratedTypeAnnotation('int/*1*/');
+
+ assertEdge(inSet(alwaysPlus), variableParam.node, hard: false);
+ }
+
Future<void> test_listLiteral_noTypeArgument_noNullableElements() async {
await analyze('''
List<String> f() {
diff --git a/pkg/nnbd_migration/test/edit_plan_test.dart b/pkg/nnbd_migration/test/edit_plan_test.dart
index 6b0cd5e..8287884 100644
--- a/pkg/nnbd_migration/test/edit_plan_test.dart
+++ b/pkg/nnbd_migration/test/edit_plan_test.dart
@@ -31,10 +31,10 @@
}
void checkPlan(EditPlan plan, String expected) {
- expect(plan.finalize().applyTo(code), expected);
+ expect(planner.finalize(plan).applyTo(code), expected);
}
- EditPlan extract(AstNode inner, AstNode outer) =>
+ NodeProducingEditPlan extract(AstNode inner, AstNode outer) =>
planner.extract(outer, planner.passThrough(inner));
Future<void> test_cascadeSearchLimit() async {
@@ -52,7 +52,7 @@
// The tests below will be based on an inner plan that adds `..isEven` after
// the `1`.
EditPlan makeInnerPlan() => planner.surround(planner.passThrough(one),
- suffix: [InsertText('..isEven')], endsInCascade: true);
+ suffix: [AtomicEdit.insert('..isEven')], endsInCascade: true);
{
// If we make a plan that passes through `c = 1`, containing a plan that
// adds `..isEven` to `1`, then we don't necessarily want to add parens yet,
@@ -154,7 +154,7 @@
await analyze('var x = 0;');
checkPlan(
planner.surround(planner.passThrough(testUnit),
- suffix: [InsertText(' var y = 0;')]),
+ suffix: [AtomicEdit.insert(' var y = 0;')]),
'var x = 0; var y = 0;');
}
@@ -162,11 +162,11 @@
await analyze('f(x) => 1..isEven;');
checkPlan(
planner.surround(planner.passThrough(findNode.cascade('..')),
- prefix: [InsertText('x..y = ')]),
+ prefix: [AtomicEdit.insert('x..y = ')]),
'f(x) => x..y = (1..isEven);');
checkPlan(
planner.surround(planner.passThrough(findNode.cascade('..')),
- prefix: [InsertText('x = ')], allowCascade: true),
+ prefix: [AtomicEdit.insert('x = ')], allowCascade: true),
'f(x) => x = 1..isEven;');
}
@@ -174,13 +174,14 @@
await analyze('var x = 1 - 2;');
checkPlan(
planner.surround(planner.passThrough(findNode.binary('-')),
- suffix: [InsertText(' - 3')],
+ suffix: [AtomicEdit.insert(' - 3')],
innerPrecedence: Precedence.additive,
associative: true),
'var x = 1 - 2 - 3;');
checkPlan(
planner.surround(planner.passThrough(findNode.binary('-')),
- prefix: [InsertText('0 - ')], innerPrecedence: Precedence.additive),
+ prefix: [AtomicEdit.insert('0 - ')],
+ innerPrecedence: Precedence.additive),
'var x = 0 - (1 - 2);');
}
@@ -188,11 +189,11 @@
await analyze('f(x) => x..y = 1;');
checkPlan(
planner.surround(planner.passThrough(findNode.integerLiteral('1')),
- suffix: [InsertText(' + 2')]),
+ suffix: [AtomicEdit.insert(' + 2')]),
'f(x) => x..y = 1 + 2;');
checkPlan(
planner.surround(planner.passThrough(findNode.integerLiteral('1')),
- suffix: [InsertText('..isEven')], endsInCascade: true),
+ suffix: [AtomicEdit.insert('..isEven')], endsInCascade: true),
'f(x) => x..y = (1..isEven);');
}
@@ -202,17 +203,17 @@
checkPlan(
planner.surround(
planner.surround(planner.passThrough(findNode.cascade('..')),
- prefix: [InsertText('1 + ')],
+ prefix: [AtomicEdit.insert('1 + ')],
innerPrecedence: Precedence.additive),
- prefix: [InsertText('true ? ')],
- suffix: [InsertText(' : 2')]),
+ prefix: [AtomicEdit.insert('true ? ')],
+ suffix: [AtomicEdit.insert(' : 2')]),
'f(a) => true ? 1 + (a..b = 0) : 2;');
checkPlan(
planner.surround(
planner.surround(planner.passThrough(findNode.cascade('..')),
- prefix: [InsertText('throw ')], allowCascade: true),
- prefix: [InsertText('true ? ')],
- suffix: [InsertText(' : 2')]),
+ prefix: [AtomicEdit.insert('throw ')], allowCascade: true),
+ prefix: [AtomicEdit.insert('true ? ')],
+ suffix: [AtomicEdit.insert(' : 2')]),
'f(a) => true ? (throw a..b = 0) : 2;');
}
@@ -220,7 +221,7 @@
await analyze('f(x, g) => g(0, throw x, 1);');
checkPlan(
planner.surround(planner.passThrough(findNode.simple('x, 1')),
- suffix: [InsertText('..y')], endsInCascade: true),
+ suffix: [AtomicEdit.insert('..y')], endsInCascade: true),
'f(x, g) => g(0, throw x..y, 1);');
}
@@ -229,16 +230,16 @@
checkPlan(
planner.surround(
planner.surround(planner.passThrough(findNode.cascade('..')),
- prefix: [InsertText('throw ')], allowCascade: true),
- prefix: [InsertText('true ? ')],
- suffix: [InsertText(' : 2')]),
+ prefix: [AtomicEdit.insert('throw ')], allowCascade: true),
+ prefix: [AtomicEdit.insert('true ? ')],
+ suffix: [AtomicEdit.insert(' : 2')]),
'f(a) => true ? (throw a..b = 0) : 2;');
checkPlan(
planner.surround(
planner.surround(planner.passThrough(findNode.integerLiteral('0')),
- prefix: [InsertText('throw ')], allowCascade: true),
- prefix: [InsertText('true ? ')],
- suffix: [InsertText(' : 2')]),
+ prefix: [AtomicEdit.insert('throw ')], allowCascade: true),
+ prefix: [AtomicEdit.insert('true ? ')],
+ suffix: [AtomicEdit.insert(' : 2')]),
'f(a) => a..b = true ? throw 0 : 2;');
}
@@ -246,12 +247,12 @@
await analyze('var x = 1 == true;');
checkPlan(
planner.surround(planner.passThrough(findNode.integerLiteral('1')),
- suffix: [InsertText(' < 2')],
+ suffix: [AtomicEdit.insert(' < 2')],
outerPrecedence: Precedence.relational),
'var x = 1 < 2 == true;');
checkPlan(
planner.surround(planner.passThrough(findNode.integerLiteral('1')),
- suffix: [InsertText(' == 2')],
+ suffix: [AtomicEdit.insert(' == 2')],
outerPrecedence: Precedence.equality),
'var x = (1 == 2) == true;');
}
@@ -260,7 +261,7 @@
await analyze('var x = 1;');
checkPlan(
planner.surround(planner.passThrough(findNode.integerLiteral('1')),
- prefix: [InsertText('throw ')]),
+ prefix: [AtomicEdit.insert('throw ')]),
'var x = throw 1;');
}
@@ -268,7 +269,7 @@
await analyze('var x = 1;');
checkPlan(
planner.surround(planner.passThrough(findNode.integerLiteral('1')),
- suffix: [InsertText('..isEven')]),
+ suffix: [AtomicEdit.insert('..isEven')]),
'var x = 1..isEven;');
}
@@ -276,12 +277,12 @@
await analyze('var x = 1 < 2;');
checkPlan(
planner.surround(planner.passThrough(findNode.binary('<')),
- suffix: [InsertText(' == true')],
+ suffix: [AtomicEdit.insert(' == true')],
innerPrecedence: Precedence.equality),
'var x = 1 < 2 == true;');
checkPlan(
planner.surround(planner.passThrough(findNode.binary('<')),
- suffix: [InsertText(' as bool')],
+ suffix: [AtomicEdit.insert(' as bool')],
innerPrecedence: Precedence.relational),
'var x = (1 < 2) as bool;');
}
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index fec91a2..ee03cff 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -836,7 +836,6 @@
changes: {findNode.simple('y +'): isNullCheck});
}
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39642')
Future<void> test_binaryExpression_question_question_nullChecked() async {
await analyze('''
Object/*!*/ _f(int/*?*/ x, double/*?*/ y) {
@@ -1385,7 +1384,6 @@
visitSubexpression(findNode.postfix('++'), '_C');
}
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38833')
Future<void>
test_postfixExpression_combined_nullable_noProblem_dynamic() async {
await analyze('''
diff --git a/runtime/bin/dart_embedder_api_impl.cc b/runtime/bin/dart_embedder_api_impl.cc
index a7fde47..6af5d82 100644
--- a/runtime/bin/dart_embedder_api_impl.cc
+++ b/runtime/bin/dart_embedder_api_impl.cc
@@ -69,8 +69,8 @@
Dart_Isolate CreateVmServiceIsolate(const IsolateCreationData& data,
const VmServiceConfiguration& config,
- const uint8_t* kernel_buffer,
- intptr_t kernel_buffer_size,
+ const uint8_t* isolate_data,
+ const uint8_t* isolate_instr,
char** error) {
if (data.flags == nullptr) {
*error = strdup("Expected non-null flags");
@@ -78,6 +78,40 @@
}
data.flags->load_vmservice_library = true;
+ Dart_Isolate service_isolate = Dart_CreateIsolateGroup(
+ data.script_uri, data.main, isolate_data, isolate_instr, data.flags,
+ data.isolate_group_data, data.isolate_data, error);
+ if (service_isolate == nullptr) {
+ return nullptr;
+ }
+
+ Dart_EnterScope();
+ // Load embedder specific bits and return.
+ if (!bin::VmService::Setup(config.ip, config.port, config.dev_mode,
+ config.disable_auth_codes,
+ config.write_service_info_filename,
+ /*trace_loading=*/false, config.deterministic)) {
+ *error = strdup(bin::VmService::GetErrorMessage());
+ return nullptr;
+ }
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+ return service_isolate;
+}
+
+Dart_Isolate CreateVmServiceIsolateFromKernel(
+ const IsolateCreationData& data,
+ const VmServiceConfiguration& config,
+ const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_size,
+ char** error) {
+ if (data.flags == nullptr) {
+ *error = strdup("Expected non-null flags");
+ return nullptr;
+ }
+ data.flags->load_vmservice_library = true;
+
Dart_Isolate service_isolate = Dart_CreateIsolateGroupFromKernel(
data.script_uri, data.main, kernel_buffer, kernel_buffer_size, data.flags,
data.isolate_group_data, data.isolate_data, error);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index aff0896..6b5ccdf 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -857,12 +857,18 @@
*
* \return NULL if successful. Returns an error message otherwise.
* The caller is responsible for freeing the error message.
+ *
+ * NOTE: This call does not store references to the passed in c-strings.
*/
DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_SetVMFlags(int argc,
const char** argv);
/**
- * Returns true if the named VM flag is set.
+ * Returns true if the named VM flag is of boolean type, specified, and set to
+ * true.
+ *
+ * \param flag_name The name of the flag without leading punctuation
+ * (example: "enable_asserts").
*/
DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name);
diff --git a/runtime/include/dart_embedder_api.h b/runtime/include/dart_embedder_api.h
index 5b283ca..c9860dd 100644
--- a/runtime/include/dart_embedder_api.h
+++ b/runtime/include/dart_embedder_api.h
@@ -70,18 +70,28 @@
bool disable_auth_codes;
};
-// Create and initialize vm-service isolate. This method should be used
-// when VM invokes isolate creation callback with DART_VM_SERVICE_ISOLATE_NAME
-// as script_uri.
-// The isolate is created from the given kernel binary that is expected to
-// contain all necessary vmservice libraries.
+// Create and initialize vm-service isolate from the given AOT snapshot, which
+// is expected to contain all necessary 'vm-service' libraries.
+// This method should be used when VM invokes isolate creation callback with
+// DART_VM_SERVICE_ISOLATE_NAME as script_uri.
DART_WARN_UNUSED_RESULT Dart_Isolate
CreateVmServiceIsolate(const IsolateCreationData& data,
const VmServiceConfiguration& config,
- const uint8_t* kernel_buffer,
- intptr_t kernel_buffer_size,
+ const uint8_t* isolate_data,
+ const uint8_t* isolate_instr,
char** error);
+// Create and initialize vm-service isolate from the given kernel binary, which
+// is expected to contain all necessary 'vm-service' libraries.
+// This method should be used when VM invokes isolate creation callback with
+// DART_VM_SERVICE_ISOLATE_NAME as script_uri.
+DART_WARN_UNUSED_RESULT Dart_Isolate
+CreateVmServiceIsolateFromKernel(const IsolateCreationData& data,
+ const VmServiceConfiguration& config,
+ const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_size,
+ char** error);
+
} // namespace embedder
} // namespace dart
diff --git a/runtime/observatory/lib/object_graph.dart b/runtime/observatory/lib/object_graph.dart
index 18426bb..1bf79ca 100644
--- a/runtime/observatory/lib/object_graph.dart
+++ b/runtime/observatory/lib/object_graph.dart
@@ -335,9 +335,15 @@
_VerticesIterator(this._graph);
bool moveNext() {
- if (_nextId == _graph._N) return false;
- current = new _SnapshotObject._(_nextId++, _graph, "");
- return true;
+ while (_nextId <= _graph._N) {
+ // A retained size of zero means the object was unreachable.
+ if (_graph._retainedSizes[_nextId] != 0) {
+ current = new _SnapshotObject._(_nextId++, _graph, "");
+ return true;
+ }
+ _nextId++;
+ }
+ return false;
}
}
@@ -360,8 +366,10 @@
_InstancesIterator(this._graph, this._cid);
bool moveNext() {
- while (_nextId < _graph._N) {
- if (_graph._cids[_nextId] == _cid) {
+ while (_nextId <= _graph._N) {
+ // A retained size of zero means the object was unreachable.
+ if (_graph._cids[_nextId] == _cid &&
+ _graph._retainedSizes[_nextId] != 0) {
current = new _SnapshotObject._(_nextId++, _graph, "");
return true;
}
@@ -1177,10 +1185,13 @@
cls.liveInstanceCount++;
}
- // Start with retained size as shallow size + external size.
+ // Start with retained size as shallow size + external size. For reachable
+ // objects only; leave unreachable objects with a retained size of 0 so
+ // they can be filtered during graph iterations.
var retainedSizes = new Uint32List(N + 1);
- for (var i = 0; i < N + 1; i++) {
- retainedSizes[i] = internalSizes[i] + externalSizes[i];
+ for (var i = 0; i <= Nconnected; i++) {
+ var v = vertex[i];
+ retainedSizes[v] = internalSizes[v] + externalSizes[v];
}
// In post order (bottom up), add retained size to dominator's retained
diff --git a/runtime/observatory/tests/service/object_graph_vm_test.dart b/runtime/observatory/tests/service/object_graph_vm_test.dart
index dd4b936..5458b49 100644
--- a/runtime/observatory/tests/service/object_graph_vm_test.dart
+++ b/runtime/observatory/tests/service/object_graph_vm_test.dart
@@ -82,6 +82,69 @@
// Check that the short list retains more than the long list inside.
// and specifically, that it retains exactly itself + the long one.
expect(first.retainedSize, equals(first.shallowSize + second.shallowSize));
+
+ // Verify sizes of classes are the appropriates sums of their instances.
+ // This also verifies that the class instance iterators are visiting the
+ // correct set of objects (e.g., not including dead objects).
+ for (SnapshotClass klass in graph.classes) {
+ int shallowSum = 0;
+ int internalSum = 0;
+ int externalSum = 0;
+ for (SnapshotObject instance in klass.instances) {
+ if (instance == graph.root) {
+ // The root may have 0 self size.
+ expect(instance.internalSize, greaterThanOrEqualTo(0));
+ expect(instance.externalSize, greaterThanOrEqualTo(0));
+ expect(instance.shallowSize, greaterThanOrEqualTo(0));
+ } else {
+ // All other objects are heap objects with positive size.
+ expect(instance.internalSize, greaterThan(0));
+ expect(instance.externalSize, greaterThanOrEqualTo(0));
+ expect(instance.shallowSize, greaterThan(0));
+ }
+ expect(instance.retainedSize, greaterThan(0));
+ expect(instance.shallowSize,
+ equals(instance.internalSize + instance.externalSize));
+ shallowSum += instance.shallowSize;
+ internalSum += instance.internalSize;
+ externalSum += instance.externalSize;
+ }
+ expect(shallowSum, equals(klass.shallowSize));
+ expect(internalSum, equals(klass.internalSize));
+ expect(externalSum, equals(klass.externalSize));
+ expect(
+ klass.shallowSize, equals(klass.internalSize + klass.externalSize));
+ }
+
+ // Verify sizes of the overall graph are the appropriates sums of all
+ // instances. This also verifies that the all instances iterator is visiting
+ // the correct set of objects (e.g., not including dead objects).
+ int shallowSum = 0;
+ int internalSum = 0;
+ int externalSum = 0;
+ for (SnapshotObject instance in graph.objects) {
+ if (instance == graph.root) {
+ // The root may have 0 self size.
+ expect(instance.internalSize, greaterThanOrEqualTo(0));
+ expect(instance.externalSize, greaterThanOrEqualTo(0));
+ expect(instance.shallowSize, greaterThanOrEqualTo(0));
+ } else {
+ // All other objects are heap objects with positive size.
+ expect(instance.internalSize, greaterThan(0));
+ expect(instance.externalSize, greaterThanOrEqualTo(0));
+ expect(instance.shallowSize, greaterThan(0));
+ }
+ expect(instance.retainedSize, greaterThan(0));
+ expect(instance.shallowSize,
+ equals(instance.internalSize + instance.externalSize));
+ shallowSum += instance.shallowSize;
+ internalSum += instance.internalSize;
+ externalSum += instance.externalSize;
+ }
+ expect(shallowSum, equals(graph.size));
+ expect(internalSum, equals(graph.internalSize));
+ expect(externalSum, equals(graph.externalSize));
+ expect(graph.size, equals(graph.internalSize + graph.externalSize));
},
];
diff --git a/runtime/tests/vm/dart/arm32_boxmint_test.dart b/runtime/tests/vm/dart/arm32_boxmint_test.dart
deleted file mode 100644
index 4c33ba6..0000000
--- a/runtime/tests/vm/dart/arm32_boxmint_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-
-// Test case that tests boxing mint
-
-// VMOptions=--shared-slow-path-triggers-gc
-
-import 'dart:typed_data';
-import 'package:expect/expect.dart';
-
-final l = Uint64List(10);
-int sum = 0;
-
-foobar() {
- for (int i = 0; i < l.length; ++i) {
- sum += l[i];
- }
- Expect.equals(sum, 1481763717120);
-}
-
-main() {
- for (int i = 0; i < 10; i++) {
- l[i] = (i + 30) << 32;
- }
- foobar();
-}
diff --git a/runtime/tests/vm/dart/boxmint_test.dart b/runtime/tests/vm/dart/boxmint_test.dart
new file mode 100644
index 0000000..bcc90b0
--- /dev/null
+++ b/runtime/tests/vm/dart/boxmint_test.dart
@@ -0,0 +1,28 @@
+// 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.
+
+// Test case that tests boxing mint
+
+// VMOptions=--optimization_counter_threshold=10 --deterministic --use-slow-path --shared-slow-path-triggers-gc --stacktrace_filter=foobar
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+final gSize = 100;
+final l = Uint64List(gSize);
+int sum = 0;
+
+foobar() {
+ for (int i = 0; i < l.length; ++i) {
+ sum += l[i];
+ }
+ Expect.equals(-9223372036854775808, sum);
+}
+
+main() {
+ for (int i = 0; i < gSize; i++) {
+ l[i] = (i + 30) << 62;
+ }
+ foobar();
+}
diff --git a/runtime/tests/vm/dart/use_flag_test_helper.dart b/runtime/tests/vm/dart/use_flag_test_helper.dart
index 685fdb5..c6fa872 100644
--- a/runtime/tests/vm/dart/use_flag_test_helper.dart
+++ b/runtime/tests/vm/dart/use_flag_test_helper.dart
@@ -24,6 +24,91 @@
final aotRuntime = path.join(
buildDir, 'dart_precompiled_runtime' + (Platform.isWindows ? '.exe' : ''));
+String get clangBuildToolsDir {
+ String archDir;
+ if (Platform.isLinux) {
+ archDir = 'linux-x64';
+ } else if (Platform.isMacOS) {
+ archDir = 'mac-x64';
+ } else {
+ return null;
+ }
+ var clangDir = path.join(sdkDir, 'buildtools', archDir, 'clang', 'bin');
+ return Directory(clangDir).existsSync() ? clangDir : null;
+}
+
+Future<void> assembleSnapshot(String assemblyPath, String snapshotPath) async {
+ if (!Platform.isLinux && !Platform.isMacOS) {
+ throw "Unsupported platform ${Platform.operatingSystem} for assembling";
+ }
+
+ final ccFlags = <String>[];
+ final ldFlags = <String>[];
+ String cc = 'gcc';
+ String shared = '-shared';
+
+ if (Platform.isMacOS) {
+ cc = 'clang';
+ } else if (buildDir.endsWith('SIMARM') || buildDir.endsWith('SIMARM64')) {
+ if (clangBuildToolsDir != null) {
+ cc = path.join(clangBuildToolsDir, 'clang');
+ } else {
+ throw 'Cannot assemble for ${path.basename(buildDir)} '
+ 'without //buildtools on ${Platform.operatingSystem}';
+ }
+ }
+
+ if (Platform.isMacOS) {
+ shared = '-dynamiclib';
+ // Tell Mac linker to give up generating eh_frame from dwarf.
+ ldFlags.add('-Wl,-no_compact_unwind');
+ } else if (buildDir.endsWith('SIMARM')) {
+ ccFlags.add('--target=armv7-linux-gnueabihf');
+ } else if (buildDir.endsWith('SIMARM64')) {
+ ccFlags.add('--target=aarch64-linux-gnu');
+ }
+
+ if (buildDir.endsWith('X64') || buildDir.endsWith('SIMARM64')) {
+ ccFlags.add('-m64');
+ }
+
+ await run(cc, <String>[
+ ...ccFlags,
+ ...ldFlags,
+ shared,
+ '-nostdlib',
+ '-o',
+ snapshotPath,
+ assemblyPath,
+ ]);
+}
+
+Future<void> stripSnapshot(String snapshotPath, String strippedPath,
+ {bool forceElf = false}) async {
+ if (!Platform.isLinux && !Platform.isMacOS) {
+ throw "Unsupported platform ${Platform.operatingSystem} for stripping";
+ }
+
+ var strip = 'strip';
+
+ if ((Platform.isLinux &&
+ (buildDir.endsWith('SIMARM') || buildDir.endsWith('SIMARM64'))) ||
+ (Platform.isMacOS && forceElf)) {
+ if (clangBuildToolsDir != null) {
+ strip = path.join(clangBuildToolsDir, 'llvm-strip');
+ } else {
+ throw 'Cannot strip ELF files for ${path.basename(buildDir)} '
+ 'without //buildtools on ${Platform.operatingSystem}';
+ }
+ }
+
+ await run(strip, <String>[
+ '-o',
+ strippedPath,
+ snapshotPath,
+ ]);
+}
+
Future<ProcessResult> runHelper(String executable, List<String> args) async {
print('Running $executable ${args.join(' ')}');
@@ -82,11 +167,16 @@
return result.stderr.split(RegExp(r'[\r\n]'));
}
+const keepTempKey = 'KEEP_TEMPORARY_DIRECTORIES';
+
Future<void> withTempDir(String name, Future<void> fun(String dir)) async {
final tempDir = Directory.systemTemp.createTempSync(name);
try {
await fun(tempDir.path);
} finally {
- tempDir.deleteSync(recursive: true);
+ if (!Platform.environment.containsKey(keepTempKey) ||
+ Platform.environment[keepTempKey].isEmpty) {
+ tempDir.deleteSync(recursive: true);
+ }
}
}
diff --git a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
index 2c6b877..965590b 100644
--- a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
@@ -6,104 +6,102 @@
import "dart:io";
import "package:expect/expect.dart";
+import 'package:path/path.dart' as path;
import "package:vm/v8_snapshot_profile.dart";
-String path(List<String> segments) {
- return "/" + segments.join("/");
-}
+import 'use_flag_test_helper.dart';
-test(String sdkRoot, {bool useAsm: false}) async {
- if (Platform.isMacOS || Platform.isWindows) {
- // Missing necessary utilities.
- return;
- }
+test({String dillPath, bool useAsm, bool stripFlag, bool stripUtil}) async {
+ // The assembler may add extra unnecessary information to the compiled
+ // snapshot whether or not we generate DWARF information in the assembly, so
+ // we force the use of a utility when generating assembly.
+ if (useAsm) Expect.isTrue(stripUtil);
- // Generate the snapshot profile.
- final String thisTestPath =
- "$sdkRoot/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart";
+ // We must strip the output in some way when generating ELF snapshots,
+ // else the debugging information added will cause the test to fail.
+ if (!stripUtil) Expect.isTrue(stripFlag);
- final Directory temp = await Directory.systemTemp.createTemp();
- final String snapshotPath = temp.path + "/test.snap";
+ final tempDirPrefix = 'v8-snapshot-profile' +
+ (useAsm ? '-assembly' : '-elf') +
+ (stripFlag ? '-intstrip' : '') +
+ (stripUtil ? '-extstrip' : '');
- final List<String> precompiler2Args = [
- "--write-v8-snapshot-profile-to=${temp.path}/profile.heapsnapshot",
- thisTestPath,
- snapshotPath,
- ];
+ await withTempDir(tempDirPrefix, (String tempDir) async {
+ // Generate the snapshot profile.
+ final profilePath = path.join(tempDir, 'profile.heapsnapshot');
+ final snapshotPath = path.join(tempDir, 'test.snap');
+ final commonSnapshotArgs = [
+ if (stripFlag) '--strip',
+ "--write-v8-snapshot-profile-to=$profilePath",
+ dillPath,
+ ];
- if (useAsm) {
- precompiler2Args.insert(0, "--build-assembly");
- }
-
- ProcessResult result = await Process.run(
- "pkg/vm/tool/precompiler2",
- precompiler2Args,
- workingDirectory: sdkRoot,
- runInShell: true,
- );
-
- // The precompiler2 script tried using GCC for the wrong architecture. We
- // don't have a workaround for this now.
- if (result.exitCode != 0 && result.stderr.contains("Assembler messages")) {
- return;
- }
-
- print(precompiler2Args);
- print(result.stderr);
- print(result.stdout);
-
- Expect.equals(result.exitCode, 0);
- Expect.equals("", result.stderr);
- Expect.equals("", result.stdout);
-
- result = await Process.run("strip", [snapshotPath]);
-
- // Same issue: strip can't process a cross-compiled ELF.
- if (result.exitCode != 0 &&
- (result.stderr.contains("Unable to recognise") ||
- result.stderr.contains("non-object and non-archive"))) {
- return;
- }
-
- final V8SnapshotProfile profile = V8SnapshotProfile.fromJson(JsonDecoder()
- .convert(File("${temp.path}/profile.heapsnapshot").readAsStringSync()));
-
- // Verify that there are no "unknown" nodes. These are emitted when we see a
- // reference to an some object but no other metadata about the object was
- // recorded. We should at least record the type for every object in the graph
- // (in some cases the shallow size can legitimately be 0, e.g. for "base
- // objects").
- for (final int node in profile.nodes) {
- if (profile[node].type == "Unknown") {
- print(profile[node].id);
- }
- Expect.notEquals(profile[node].type, "Unknown");
- }
-
- // Verify that all nodes are reachable from the declared roots.
- int unreachableNodes = 0;
- Set<int> nodesReachableFromRoots = profile.preOrder(profile.root).toSet();
- for (final int node in profile.nodes) {
- if (!nodesReachableFromRoots.contains(node)) {
- ++unreachableNodes;
- }
- }
- Expect.equals(unreachableNodes, 0);
-
- // Verify that the actual size of the snapshot is close to the sum of the
- // shallow sizes of all objects in the profile. They will not be exactly equal
- // because of global headers and padding.
- final int actual = await File(snapshotPath).length();
- final int expected = profile.accountedBytes;
- print("Expected size: $expected, actual size: $actual.");
- if ((actual - expected).abs() / actual > 0.03) {
if (useAsm) {
- print("Failure on Assembly snapshot type.");
+ final assemblyPath = path.join(tempDir, 'test.S');
+
+ await run(genSnapshot, <String>[
+ '--snapshot-kind=app-aot-assembly',
+ '--assembly=$assemblyPath',
+ ...commonSnapshotArgs,
+ ]);
+
+ await assembleSnapshot(assemblyPath, snapshotPath);
} else {
- print("Failure on ELF snapshot type.");
+ await run(genSnapshot, <String>[
+ '--snapshot-kind=app-aot-elf',
+ '--elf=$snapshotPath',
+ ...commonSnapshotArgs,
+ ]);
}
- Expect.fail("Difference cannot be greater than 3% of actual.");
- }
+
+ String strippedPath;
+ if (stripUtil) {
+ strippedPath = snapshotPath + '.stripped';
+ await stripSnapshot(snapshotPath, strippedPath, forceElf: !useAsm);
+ } else {
+ strippedPath = snapshotPath;
+ }
+
+ final V8SnapshotProfile profile = V8SnapshotProfile.fromJson(
+ JsonDecoder().convert(File(profilePath).readAsStringSync()));
+
+ // Verify that there are no "unknown" nodes. These are emitted when we see a
+ // reference to an some object but no other metadata about the object was
+ // recorded. We should at least record the type for every object in the
+ // graph (in some cases the shallow size can legitimately be 0, e.g. for
+ // "base objects").
+ for (final int node in profile.nodes) {
+ Expect.notEquals(profile[node].type, "Unknown",
+ "unknown node at ID ${profile[node].id}");
+ }
+
+ // Verify that all nodes are reachable from the declared roots.
+ int unreachableNodes = 0;
+ Set<int> nodesReachableFromRoots = profile.preOrder(profile.root).toSet();
+ for (final int node in profile.nodes) {
+ Expect.isTrue(nodesReachableFromRoots.contains(node),
+ "unreachable node at ID ${profile[node].id}");
+ }
+
+ // Verify that the actual size of the snapshot is close to the sum of the
+ // shallow sizes of all objects in the profile. They will not be exactly
+ // equal because of global headers and padding.
+ final actual = await File(strippedPath).length();
+ final expected = profile.accountedBytes;
+
+ final fileType = useAsm ? "assembly" : "ELF";
+ String stripPrefix = "";
+ if (stripFlag && stripUtil) {
+ stripPrefix = "internally and externally stripped ";
+ } else if (stripFlag) {
+ stripPrefix = "internally stripped ";
+ } else if (stripUtil) {
+ stripPrefix = "externally stripped ";
+ }
+
+ Expect.approxEquals(expected, actual, 0.03 * actual,
+ "failed on $stripPrefix$fileType snapshot type.");
+ });
}
Match matchComplete(RegExp regexp, String line) {
@@ -116,14 +114,15 @@
// All fields of "Raw..." classes defined in "raw_object.h" must be included in
// the giant macro in "raw_object_fields.cc". This function attempts to check
// that with some basic regexes.
-testMacros(String sdkRoot) async {
+testMacros() async {
const String className = "([a-z0-9A-Z]+)";
const String rawClass = "Raw$className";
const String fieldName = "([a-z0-9A-Z_]+)";
final Map<String, Set<String>> fields = {};
- final String rawObjectFieldsPath = "$sdkRoot/runtime/vm/raw_object_fields.cc";
+ final String rawObjectFieldsPath =
+ path.join(sdkDir, 'runtime', 'vm', 'raw_object_fields.cc');
final RegExp fieldEntry = RegExp(" *F\\($className, $fieldName\\) *\\\\?");
await for (String line in File(rawObjectFieldsPath)
@@ -143,7 +142,8 @@
final RegExp classEnd = RegExp("}");
final RegExp field = RegExp(" $rawClass. +$fieldName;.*");
- final String rawObjectPath = "$sdkRoot/runtime/vm/raw_object.h";
+ final String rawObjectPath =
+ path.join(sdkDir, 'runtime', 'vm', 'raw_object.h');
String currentClass;
bool hasMissingFields = false;
@@ -179,21 +179,65 @@
}
if (hasMissingFields) {
- Expect.fail(
- "runtime/vm/raw_object_fields.cc misses some fields. Please update it to match raw_object.h.");
+ Expect.fail("$rawObjectFieldsPath is missing some fields. "
+ "Please update it to match $rawObjectPath.");
}
}
main() async {
- if (Platform.isWindows) return;
+ void printSkip(String description) =>
+ print('Skipping $description for ${path.basename(buildDir)} '
+ 'on ${Platform.operatingSystem}' +
+ (clangBuildToolsDir == null ? ' without //buildtools' : ''));
- final List<String> sdkBaseSegments =
- Uri.file(Platform.resolvedExecutable).pathSegments.toList();
- sdkBaseSegments
- .replaceRange(sdkBaseSegments.length - 3, sdkBaseSegments.length, []);
- String sdkRoot = path(sdkBaseSegments);
+ // We don't have access to the SDK on Android.
+ if (Platform.isAndroid) {
+ printSkip('all tests');
+ return;
+ }
- await test(sdkRoot, useAsm: true);
- await test(sdkRoot, useAsm: false);
- testMacros(sdkRoot);
+ await testMacros();
+
+ await withTempDir('v8-snapshot-profile-writer', (String tempDir) async {
+ // We only need to generate the dill file once.
+ final _thisTestPath = path.join(sdkDir, 'runtime', 'tests', 'vm', 'dart',
+ 'v8_snapshot_profile_writer_test.dart');
+ final dillPath = path.join(tempDir, 'test.dill');
+ await run(genKernel,
+ <String>['--platform', platformDill, '-o', dillPath, _thisTestPath]);
+
+ // Test stripped ELF generation directly.
+ await test(
+ dillPath: dillPath, stripFlag: true, stripUtil: false, useAsm: false);
+
+ // We neither generate assembly nor have a stripping utility on Windows.
+ if (Platform.isWindows) {
+ printSkip('external stripping and assembly tests');
+ return;
+ }
+
+ // The native strip utility on Mac OS X doesn't recognize ELF files.
+ if (Platform.isMacOS && clangBuildToolsDir == null) {
+ printSkip('ELF external stripping test');
+ } else {
+ // Test unstripped ELF generation that is then stripped externally.
+ await test(
+ dillPath: dillPath, stripFlag: false, stripUtil: true, useAsm: false);
+ }
+
+ // TODO(sstrickl): Currently we can't assemble for SIMARM64 on MacOSX.
+ // For example, the test runner still uses blobs for dartkp-mac-*-simarm64.
+ // Change assembleSnapshot and remove this check when we can.
+ if (Platform.isMacOS && buildDir.endsWith('SIMARM64')) {
+ printSkip('assembly tests');
+ return;
+ }
+
+ // Test stripped assembly generation that is then compiled and stripped.
+ await test(
+ dillPath: dillPath, stripFlag: true, stripUtil: true, useAsm: true);
+ // Test unstripped assembly generation that is then compiled and stripped.
+ await test(
+ dillPath: dillPath, stripFlag: false, stripUtil: true, useAsm: true);
+ });
}
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index 2326327..3807646 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -14,7 +14,7 @@
// Version of DartFuzz. Increase this each time changes are made
// to preserve the property that a given version of DartFuzz yields
// the same fuzzed program for a deterministic random seed.
-const String version = '1.84';
+const String version = '1.85';
// Restriction on statements and expressions.
const int stmtDepth = 1;
diff --git a/runtime/tools/dartfuzz/dartfuzz_type_table.dart b/runtime/tools/dartfuzz/dartfuzz_type_table.dart
index ede65ee..6e15099 100644
--- a/runtime/tools/dartfuzz/dartfuzz_type_table.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_type_table.dart
@@ -63517,12 +63517,6 @@
FLOAT32X4,
],
},
- '/': {
- [
- FLOAT32X4,
- FLOAT32X4,
- ],
- },
'??': {
[
FLOAT32X4,
@@ -63549,12 +63543,6 @@
FLOAT64X2,
],
},
- '/': {
- [
- FLOAT64X2,
- FLOAT64X2,
- ],
- },
'??': {
[
FLOAT64X2,
@@ -64981,9 +64969,6 @@
'*=': {
FLOAT32X4,
},
- '/=': {
- FLOAT32X4,
- },
},
FLOAT32X4LIST: {
'=': {
@@ -65017,9 +65002,6 @@
'*=': {
FLOAT64X2,
},
- '/=': {
- FLOAT64X2,
- },
},
FLOAT64X2LIST: {
'=': {
@@ -139751,12 +139733,6 @@
DartType.FLOAT32X4,
],
},
- '/': {
- [
- DartType.FLOAT32X4,
- DartType.FLOAT32X4,
- ],
- },
'??': {
[
DartType.FLOAT32X4,
@@ -139783,12 +139759,6 @@
DartType.FLOAT64X2,
],
},
- '/': {
- [
- DartType.FLOAT64X2,
- DartType.FLOAT64X2,
- ],
- },
'??': {
[
DartType.FLOAT64X2,
@@ -140247,9 +140217,6 @@
'*=': {
DartType.FLOAT32X4,
},
- '/=': {
- DartType.FLOAT32X4,
- },
},
DartType.FLOAT32X4LIST: {
'=': {
@@ -140283,9 +140250,6 @@
'*=': {
DartType.FLOAT64X2,
},
- '/=': {
- DartType.FLOAT64X2,
- },
},
DartType.FLOAT64X2LIST: {
'=': {
diff --git a/runtime/tools/dartfuzz/gen_type_table.dart b/runtime/tools/dartfuzz/gen_type_table.dart
index 2d5243a..0dfae17 100644
--- a/runtime/tools/dartfuzz/gen_type_table.dart
+++ b/runtime/tools/dartfuzz/gen_type_table.dart
@@ -866,6 +866,20 @@
}
}
+// Filters methods based on a manually maintained blacklist.
+//
+// Blacklisted methods should be associated with an issue number so they can be
+// re-enabled after the issue is resolved.
+bool isBlacklistedMethod(InterfaceType tp, MethodElement method) {
+ // TODO(bkonyi): Enable operator / for these types after we resolve
+ // https://github.com/dart-lang/sdk/issues/39890
+ if (((tp.displayName == 'Float32x4') && (method.name == '/')) ||
+ ((tp.displayName == 'Float64x2') && (method.name == '/'))) {
+ return true;
+ }
+ return false;
+}
+
// Extract all binary and unary operators for tp.
// Operators are stored by return type in the following way:
// return type: { operator: { parameter types } }
@@ -874,6 +888,9 @@
// Does not recurse into interfaces and superclasses of tp.
void getOperatorsForTyp(String typName, InterfaceType tp, fromLiteral) {
for (MethodElement method in tp.methods) {
+ // If the method is manually blacklisted, skip it.
+ if (isBlacklistedMethod(tp, method)) continue;
+
// Detect whether tp can be parsed from a literal (dartfuzz.dart can
// already handle that).
// This is usually indicated by the presence of the static constructor
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 721a931..5084ee1 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -1894,6 +1894,48 @@
}
}
+bool Assembler::CanGenerateXCbzTbz(Register rn, Condition cond) {
+ if (rn == CSP) {
+ return false;
+ }
+ switch (cond) {
+ case EQ: // equal
+ case NE: // not equal
+ case MI: // minus/negative
+ case LT: // signed less than
+ case PL: // plus/positive or zero
+ case GE: // signed greater than or equal
+ return true;
+ default:
+ return false;
+ }
+}
+
+void Assembler::GenerateXCbzTbz(Register rn, Condition cond, Label* label) {
+ constexpr int32_t bit_no = 63;
+ constexpr OperandSize sz = kDoubleWord;
+ ASSERT(rn != CSP);
+ switch (cond) {
+ case EQ: // equal
+ cbz(label, rn, sz);
+ return;
+ case NE: // not equal
+ cbnz(label, rn, sz);
+ return;
+ case MI: // minus/negative
+ case LT: // signed less than
+ tbnz(label, rn, bit_no);
+ return;
+ case PL: // plus/positive or zero
+ case GE: // signed greater than or equal
+ tbz(label, rn, bit_no);
+ return;
+ default:
+ // Only conditions above allow single instruction emission.
+ UNREACHABLE();
+ }
+}
+
} // namespace compiler
} // namespace dart
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 0493e08..48d5c06 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1002,6 +1002,11 @@
EmitCompareAndBranch(CBNZ, rt, label, sz);
}
+ // Generate 64-bit compare with zero and branch when condition allows to use
+ // a single instruction: cbz/cbnz/tbz/tbnz.
+ bool CanGenerateXCbzTbz(Register rn, Condition cond);
+ void GenerateXCbzTbz(Register rn, Condition cond, Label* label);
+
// Test bit and branch if zero.
void tbz(Label* label, Register rt, intptr_t bit_number) {
EmitTestAndBranch(TBZ, rt, bit_number, label);
diff --git a/runtime/vm/compiler/backend/compile_type.h b/runtime/vm/compiler/backend/compile_type.h
index 9aa145d..dc2e64c 100644
--- a/runtime/vm/compiler/backend/compile_type.h
+++ b/runtime/vm/compiler/backend/compile_type.h
@@ -57,6 +57,7 @@
return *this;
}
+ // TODO(regis): Should we also consider type_.nullability() here?
bool is_nullable() const { return is_nullable_; }
// Return type such that concrete value's type in runtime is guaranteed to
diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc
index 3592d56..1016626 100644
--- a/runtime/vm/compiler/backend/constant_propagator.cc
+++ b/runtime/vm/compiler/backend/constant_propagator.cc
@@ -798,8 +798,8 @@
Definition* def = instr->value()->definition();
const Object& value = def->constant_value();
const AbstractType& checked_type = instr->type();
- // TODO(regis): Revisit the evaluation of the type test.
- if (checked_type.IsTopType()) {
+ // If the checked type is a top type, the result is always true.
+ if (checked_type.IsTopType(instr->nnbd_mode())) {
SetValue(instr, Bool::True());
} else if (IsNonConstant(value)) {
intptr_t value_cid = instr->value()->definition()->Type()->ToCid();
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 021fbbe..521bc11 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -504,10 +504,12 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
+ // TODO(regis): Revisit the bound check taking NNBD into consideration.
+ // TODO(alexmarkov): Fix issue #40066.
// If it's guaranteed, by type-parameter bound, that the type parameter will
// never have a value of a function type, then we can safely do a 4-type
// test instead of a 6-type test.
- auto test_kind = !bound.IsTopType() && !bound.IsFunctionType() &&
+ auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
!bound.IsDartFunctionType() && bound.IsType()
? kTestTypeSixArgs
: kTestTypeFourArgs;
@@ -611,7 +613,7 @@
// If instanceof type test cannot be performed successfully at compile time and
// therefore eliminated, optimize it by adding inlined tests for:
-// - NULL -> return type == Null (type is not Object or dynamic).
+// - Null -> see comment below.
// - Smi -> compile time subtype check (only if dst class is not parameterized).
// - Class equality (only if class is not parameterized).
// Inputs:
@@ -626,24 +628,39 @@
NNBDMode mode,
LocationSummary* locs) {
ASSERT(type.IsFinalized());
- ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
+ ASSERT(!type.IsTopType(mode)); // Already checked.
const Register kInstantiatorTypeArgumentsReg = R2;
const Register kFunctionTypeArgumentsReg = R1;
__ PushList((1 << kInstantiatorTypeArgumentsReg) |
(1 << kFunctionTypeArgumentsReg));
+
compiler::Label is_instance, is_not_instance;
- // If type is instantiated and non-parameterized, we can inline code
- // checking whether the tested instance is a Smi.
- if (type.IsInstantiated()) {
- // A null object is only an instance of Null, Object, and dynamic.
- // Object and dynamic have already been checked above (if the type is
- // instantiated). So we can return false here if the instance is null,
- // unless the type is Null (and if the type is instantiated).
- // We can only inline this null check if the type is instantiated at compile
- // time, since an uninstantiated type at compile time could be Null, Object,
- // or dynamic at run time.
- __ CompareObject(R0, Object::null_object());
- __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ);
+ // 'null' is an instance of Null, Object*, Object?, void, and dynamic.
+ // In addition, 'null' is an instance of Never and Object with legacy testing,
+ // or of any nullable or legacy type with nnbd testing.
+ // It is also an instance of FutureOr<T> if it is an instance of T.
+ if (mode == NNBDMode::kLegacyLib) {
+ // See Legacy_NullIsInstanceOf().
+ if (type.IsInstantiated()) {
+ AbstractType& type_arg = AbstractType::Handle(type.raw());
+ while (type_arg.IsFutureOr(&type_arg)) {
+ }
+ __ CompareObject(R0, Object::null_object());
+ __ b((type_arg.IsNullType() || type_arg.Legacy_IsTopType())
+ ? &is_instance
+ : &is_not_instance,
+ EQ);
+ }
+ } else {
+ ASSERT(mode == NNBDMode::kOptedInLib);
+ // Test is valid on uninstantiated type, unless nullability is undetermined.
+ // See NNBD_NullIsInstanceOf().
+ if (!type.IsUndetermined()) {
+ __ CompareObject(R0, Object::null_object());
+ __ b((type.IsNullable() || type.IsLegacy()) ? &is_instance
+ : &is_not_instance,
+ EQ);
+ }
}
// Generate inline instanceof test.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 9e8c06b..b4ee10f 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -483,10 +483,12 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
+ // TODO(regis): Revisit the bound check taking NNBD into consideration.
+ // TODO(alexmarkov): Fix issue #40066.
// If it's guaranteed, by type-parameter bound, that the type parameter will
// never have a value of a function type, then we can safely do a 4-type
// test instead of a 6-type test.
- auto test_kind = !bound.IsTopType() && !bound.IsFunctionType() &&
+ auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
!bound.IsDartFunctionType() && bound.IsType()
? kTestTypeSixArgs
: kTestTypeFourArgs;
@@ -588,7 +590,7 @@
// If instanceof type test cannot be performed successfully at compile time and
// therefore eliminated, optimize it by adding inlined tests for:
-// - NULL -> return type == Null (type is not Object or dynamic).
+// - Null -> see comment below.
// - Smi -> compile time subtype check (only if dst class is not parameterized).
// - Class equality (only if class is not parameterized).
// Inputs:
@@ -603,23 +605,38 @@
NNBDMode mode,
LocationSummary* locs) {
ASSERT(type.IsFinalized());
- ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
+ ASSERT(!type.IsTopType(mode)); // Already checked.
const Register kInstantiatorTypeArgumentsReg = R1;
const Register kFunctionTypeArgumentsReg = R2;
__ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
+
compiler::Label is_instance, is_not_instance;
- // If type is instantiated and non-parameterized, we can inline code
- // checking whether the tested instance is a Smi.
- if (type.IsInstantiated()) {
- // A null object is only an instance of Null, Object, and dynamic.
- // Object and dynamic have already been checked above (if the type is
- // instantiated). So we can return false here if the instance is null,
- // unless the type is Null (and if the type is instantiated).
- // We can only inline this null check if the type is instantiated at compile
- // time, since an uninstantiated type at compile time could be Null, Object,
- // or dynamic at run time.
- __ CompareObject(R0, Object::null_object());
- __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ);
+ // 'null' is an instance of Null, Object*, Object?, void, and dynamic.
+ // In addition, 'null' is an instance of Never and Object with legacy testing,
+ // or of any nullable or legacy type with nnbd testing.
+ // It is also an instance of FutureOr<T> if it is an instance of T.
+ if (mode == NNBDMode::kLegacyLib) {
+ // See Legacy_NullIsInstanceOf().
+ if (type.IsInstantiated()) {
+ AbstractType& type_arg = AbstractType::Handle(type.raw());
+ while (type_arg.IsFutureOr(&type_arg)) {
+ }
+ __ CompareObject(R0, Object::null_object());
+ __ b((type_arg.IsNullType() || type_arg.Legacy_IsTopType())
+ ? &is_instance
+ : &is_not_instance,
+ EQ);
+ }
+ } else {
+ ASSERT(mode == NNBDMode::kOptedInLib);
+ // Test is valid on uninstantiated type, unless nullability is undetermined.
+ // See NNBD_NullIsInstanceOf().
+ if (!type.IsUndetermined()) {
+ __ CompareObject(R0, Object::null_object());
+ __ b((type.IsNullable() || type.IsLegacy()) ? &is_instance
+ : &is_not_instance,
+ EQ);
+ }
}
// Generate inline instanceof test.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index d62d585..594ac84 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -482,9 +482,11 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
+ // TODO(regis): Revisit the bound check taking NNBD into consideration.
+ // TODO(alexmarkov): Fix issue #40066.
// If it's guaranteed, by type-parameter bound, that the type parameter will
// never have a value of a function type.
- auto test_kind = !bound.IsTopType() && !bound.IsFunctionType() &&
+ auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
!bound.IsDartFunctionType() && bound.IsType()
? kTestTypeSixArgs
: kTestTypeFourArgs;
@@ -590,7 +592,7 @@
// If instanceof type test cannot be performed successfully at compile time and
// therefore eliminated, optimize it by adding inlined tests for:
-// - NULL -> return type == Null (type is not Object or dynamic).
+// - Null -> see comment below.
// - Smi -> compile time subtype check (only if dst class is not parameterized).
// - Class equality (only if class is not parameterized).
// Inputs:
@@ -605,7 +607,7 @@
NNBDMode mode,
LocationSummary* locs) {
ASSERT(type.IsFinalized());
- ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
+ ASSERT(!type.IsTopType(mode)); // Already checked.
__ pushl(EDX); // Store instantiator type arguments.
__ pushl(ECX); // Store function type arguments.
@@ -613,18 +615,30 @@
const compiler::Immediate& raw_null =
compiler::Immediate(reinterpret_cast<intptr_t>(Object::null()));
compiler::Label is_instance, is_not_instance;
- // If type is instantiated and non-parameterized, we can inline code
- // checking whether the tested instance is a Smi.
- if (type.IsInstantiated()) {
- // A null object is only an instance of Null, Object, and dynamic.
- // Object and dynamic have already been checked above (if the type is
- // instantiated). So we can return false here if the instance is null,
- // unless the type is Null (and if the type is instantiated).
- // We can only inline this null check if the type is instantiated at compile
- // time, since an uninstantiated type at compile time could be Null, Object,
- // or dynamic at run time.
- __ cmpl(EAX, raw_null);
- __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance);
+ // 'null' is an instance of Null, Object*, Object?, void, and dynamic.
+ // In addition, 'null' is an instance of Never and Object with legacy testing,
+ // or of any nullable or legacy type with nnbd testing.
+ // It is also an instance of FutureOr<T> if it is an instance of T.
+ if (mode == NNBDMode::kLegacyLib) {
+ // See Legacy_NullIsInstanceOf().
+ if (type.IsInstantiated()) {
+ AbstractType& type_arg = AbstractType::Handle(type.raw());
+ while (type_arg.IsFutureOr(&type_arg)) {
+ }
+ __ cmpl(EAX, raw_null);
+ __ j(EQUAL, (type_arg.IsNullType() || type_arg.Legacy_IsTopType())
+ ? &is_instance
+ : &is_not_instance);
+ }
+ } else {
+ ASSERT(mode == NNBDMode::kOptedInLib);
+ // Test is valid on uninstantiated type, unless nullability is undetermined.
+ // See NNBD_NullIsInstanceOf().
+ if (!type.IsUndetermined()) {
+ __ cmpl(EAX, raw_null);
+ __ j(EQUAL, (type.IsNullable() || type.IsLegacy()) ? &is_instance
+ : &is_not_instance);
+ }
}
// Generate inline instanceof test.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 735fc46..9485ea4 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -509,10 +509,12 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
+ // TODO(regis): Revisit the bound check taking NNBD into consideration.
+ // TODO(alexmarkov): Fix issue #40066.
// If it's guaranteed, by type-parameter bound, that the type parameter will
// never have a value of a function type, then we can safely do a 4-type
// test instead of a 6-type test.
- auto test_kind = !bound.IsTopType() && !bound.IsFunctionType() &&
+ auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
!bound.IsDartFunctionType() && bound.IsType()
? kTestTypeSixArgs
: kTestTypeFourArgs;
@@ -612,7 +614,7 @@
// If instanceof type test cannot be performed successfully at compile time and
// therefore eliminated, optimize it by adding inlined tests for:
-// - NULL -> return type == Null (type is not Object or dynamic).
+// - Null -> see comment below.
// - Smi -> compile time subtype check (only if dst class is not parameterized).
// - Class equality (only if class is not parameterized).
// Inputs:
@@ -627,21 +629,33 @@
NNBDMode mode,
LocationSummary* locs) {
ASSERT(type.IsFinalized());
- ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
+ ASSERT(!type.IsTopType(mode)); // Already checked.
compiler::Label is_instance, is_not_instance;
- // If type is instantiated and non-parameterized, we can inline code
- // checking whether the tested instance is a Smi.
- if (type.IsInstantiated()) {
- // A null object is only an instance of Null, Object, void and dynamic.
- // Object void and dynamic have already been checked above (if the type is
- // instantiated). So we can return false here if the instance is null,
- // unless the type is Null (and if the type is instantiated).
- // We can only inline this null check if the type is instantiated at compile
- // time, since an uninstantiated type at compile time could be Null, Object,
- // or dynamic at run time.
- __ CompareObject(RAX, Object::null_object());
- __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance);
+ // 'null' is an instance of Null, Object*, Object?, void, and dynamic.
+ // In addition, 'null' is an instance of Never and Object with legacy testing,
+ // or of any nullable or legacy type with nnbd testing.
+ // It is also an instance of FutureOr<T> if it is an instance of T.
+ if (mode == NNBDMode::kLegacyLib) {
+ // See Legacy_NullIsInstanceOf().
+ if (type.IsInstantiated()) {
+ AbstractType& type_arg = AbstractType::Handle(type.raw());
+ while (type_arg.IsFutureOr(&type_arg)) {
+ }
+ __ CompareObject(RAX, Object::null_object());
+ __ j(EQUAL, (type_arg.IsNullType() || type_arg.Legacy_IsTopType())
+ ? &is_instance
+ : &is_not_instance);
+ }
+ } else {
+ ASSERT(mode == NNBDMode::kOptedInLib);
+ // Test is valid on uninstantiated type, unless nullability is undetermined.
+ // See NNBD_NullIsInstanceOf().
+ if (!type.IsUndetermined()) {
+ __ CompareObject(RAX, Object::null_object());
+ __ j(EQUAL, (type.IsNullable() || type.IsLegacy()) ? &is_instance
+ : &is_not_instance);
+ }
}
// Generate inline instanceof test.
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 6bdb4d3..d78a065 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -3242,21 +3242,14 @@
}
static bool MayBeNumber(CompileType* type) {
- // TODO(regis): Does this function depend on NNBDMode?
if (type->IsNone()) {
return false;
}
auto& compile_type = AbstractType::Handle(type->ToAbstractType()->raw());
- if (compile_type.IsType() &&
- Class::Handle(compile_type.type_class()).IsFutureOrClass()) {
- const auto& type_args = TypeArguments::Handle(compile_type.arguments());
- if (type_args.IsNull()) {
- return true;
- }
- compile_type = type_args.TypeAt(0);
+ while (compile_type.IsFutureOr(&compile_type)) {
}
// Note that type 'Number' is a subtype of itself.
- return compile_type.IsTopType() || compile_type.IsTypeParameter() ||
+ return compile_type.Legacy_IsTopType() || compile_type.IsTypeParameter() ||
compile_type.IsSubtypeOf(NNBDMode::kLegacyLib,
Type::Handle(Type::Number()), Heap::kOld);
}
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 2f5a6e9..45a4987 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -638,9 +638,48 @@
}
}
+static bool AreLabelsNull(BranchLabels labels) {
+ return (labels.true_label == nullptr && labels.false_label == nullptr &&
+ labels.fall_through == nullptr);
+}
+
+static bool CanUseCbzTbzForComparison(FlowGraphCompiler* compiler,
+ Register rn,
+ Condition cond,
+ BranchLabels labels) {
+ return !AreLabelsNull(labels) && __ CanGenerateXCbzTbz(rn, cond);
+}
+
+static void EmitCbzTbz(Register reg,
+ FlowGraphCompiler* compiler,
+ Condition true_condition,
+ BranchLabels labels) {
+ ASSERT(CanUseCbzTbzForComparison(compiler, reg, true_condition, labels));
+ if (labels.fall_through == labels.false_label) {
+ // If the next block is the false successor we will fall through to it.
+ __ GenerateXCbzTbz(reg, true_condition, labels.true_label);
+ } else {
+ // If the next block is not the false successor we will branch to it.
+ Condition false_condition = NegateCondition(true_condition);
+ __ GenerateXCbzTbz(reg, false_condition, labels.false_label);
+
+ // Fall through or jump to the true successor.
+ if (labels.fall_through != labels.true_label) {
+ __ b(labels.true_label);
+ }
+ }
+}
+
+// Similar to ComparisonInstr::EmitComparisonCode, may either:
+// - emit comparison code and return a valid condition in which case the
+// caller is expected to emit a branch to the true label based on that
+// condition (or a branch to the false label on the opposite condition).
+// - emit comparison code with a branch directly to the labels and return
+// kInvalidCondition.
static Condition EmitInt64ComparisonOp(FlowGraphCompiler* compiler,
LocationSummary* locs,
- Token::Kind kind) {
+ Token::Kind kind,
+ BranchLabels labels) {
Location left = locs->in(0);
Location right = locs->in(1);
ASSERT(!left.IsConstant() || !right.IsConstant());
@@ -660,6 +699,13 @@
}
if (right_constant->IsUnboxedSignedIntegerConstant()) {
+ const int64_t constant =
+ right_constant->GetUnboxedSignedIntegerConstantValue();
+ if (constant == 0 && CanUseCbzTbzForComparison(compiler, left.reg(),
+ true_condition, labels)) {
+ EmitCbzTbz(left.reg(), compiler, true_condition, labels);
+ return kInvalidCondition;
+ }
__ CompareImmediate(
left.reg(), right_constant->GetUnboxedSignedIntegerConstantValue());
} else {
@@ -741,7 +787,7 @@
Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
BranchLabels labels) {
if (operation_cid() == kSmiCid || operation_cid() == kMintCid) {
- return EmitInt64ComparisonOp(compiler, locs(), kind());
+ return EmitInt64ComparisonOp(compiler, locs(), kind(), labels);
} else {
ASSERT(operation_cid() == kDoubleCid);
return EmitDoubleComparisonOp(compiler, locs(), labels, kind());
@@ -862,7 +908,7 @@
Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
BranchLabels labels) {
if (operation_cid() == kSmiCid || operation_cid() == kMintCid) {
- return EmitInt64ComparisonOp(compiler, locs(), kind());
+ return EmitInt64ComparisonOp(compiler, locs(), kind(), labels);
} else {
ASSERT(operation_cid() == kDoubleCid);
return EmitDoubleComparisonOp(compiler, locs(), labels, kind());
@@ -3385,7 +3431,7 @@
Condition CheckedSmiComparisonInstr::EmitComparisonCode(
FlowGraphCompiler* compiler,
BranchLabels labels) {
- return EmitInt64ComparisonOp(compiler, locs(), kind());
+ return EmitInt64ComparisonOp(compiler, locs(), kind(), labels);
}
#define EMIT_SMI_CHECK \
@@ -3414,8 +3460,9 @@
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
- ASSERT(true_condition != kInvalidCondition);
- EmitBranchOnCondition(compiler, true_condition, labels);
+ if (true_condition != kInvalidCondition) {
+ EmitBranchOnCondition(compiler, true_condition, labels);
+ }
// No need to bind slow_path->exit_label() as slow path exits through
// true/false branch labels.
}
@@ -3435,8 +3482,9 @@
compiler->AddSlowPathCode(slow_path);
EMIT_SMI_CHECK;
Condition true_condition = EmitComparisonCode(compiler, labels);
- ASSERT(true_condition != kInvalidCondition);
- EmitBranchOnCondition(compiler, true_condition, labels);
+ if (true_condition != kInvalidCondition) {
+ EmitBranchOnCondition(compiler, true_condition, labels);
+ }
Register result = locs()->out(0).reg();
__ Bind(false_label);
__ LoadObject(result, Bool::False());
@@ -3928,13 +3976,35 @@
bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
- LocationSummary* summary = new (zone)
- LocationSummary(zone, kNumInputs, kNumTemps,
- ValueFitsSmi() ? LocationSummary::kNoCall
- : LocationSummary::kCallOnSlowPath);
+ // Shared slow path is used in BoxInt64Instr::EmitNativeCode in
+ // FLAG_use_bare_instructions mode and only after VM isolate stubs where
+ // replaced with isolate-specific stubs.
+ const bool stubs_in_vm_isolate = (Isolate::Current()
+ ->object_store()
+ ->allocate_mint_with_fpu_regs_stub()
+ ->InVMIsolateHeap() ||
+ Isolate::Current()
+ ->object_store()
+ ->allocate_mint_without_fpu_regs_stub()
+ ->InVMIsolateHeap());
+ const bool shared_slow_path_call = SlowPathSharingSupported(opt) &&
+ FLAG_use_bare_instructions &&
+ !stubs_in_vm_isolate;
+ LocationSummary* summary = new (zone) LocationSummary(
+ zone, kNumInputs, kNumTemps,
+ ValueFitsSmi()
+ ? LocationSummary::kNoCall
+ : shared_slow_path_call ? LocationSummary::kCallOnSharedSlowPath
+ : LocationSummary::kCallOnSlowPath);
+
summary->set_in(0, Location::RequiresRegister());
- summary->set_out(0, Location::RequiresRegister());
- if (!ValueFitsSmi()) {
+ if (ValueFitsSmi()) {
+ summary->set_out(0, Location::RequiresRegister());
+ } else if (shared_slow_path_call) {
+ summary->set_out(0, Location::RegisterLocation(R0));
+ summary->set_temp(0, Location::RegisterLocation(R1));
+ } else {
+ summary->set_out(0, Location::RequiresRegister());
summary->set_temp(0, Location::RequiresRegister());
}
return summary;
@@ -3947,7 +4017,6 @@
__ SmiTag(out, in);
return;
}
-
ASSERT(kSmiTag == 0);
__ LslImmediate(out, in, kSmiTagSize);
compiler::Label done;
@@ -3955,8 +4024,37 @@
__ b(&done, EQ);
Register temp = locs()->temp(0).reg();
- BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(), out,
- temp);
+
+ if (compiler->intrinsic_mode()) {
+ __ TryAllocate(compiler->mint_class(),
+ compiler->intrinsic_slow_path_label(), out, temp);
+ } else {
+ if (locs()->call_on_shared_slow_path()) {
+ auto object_store = compiler->isolate()->object_store();
+ const bool live_fpu_regs =
+ locs()->live_registers()->FpuRegisterCount() > 0;
+ const auto& stub = Code::ZoneHandle(
+ compiler->zone(),
+ live_fpu_regs ? object_store->allocate_mint_with_fpu_regs_stub()
+ : object_store->allocate_mint_without_fpu_regs_stub());
+ // BoxInt64Instr uses shared slow path only if stub can be reached
+ // via PC-relative call.
+ ASSERT(FLAG_use_bare_instructions);
+ ASSERT(!stub.InVMIsolateHeap());
+ __ GenerateUnRelocatedPcRelativeCall();
+ compiler->AddPcRelativeCallStubTarget(stub);
+
+ ASSERT(!locs()->live_registers()->ContainsRegister(R0));
+
+ auto extended_env = compiler->SlowPathEnvironmentFor(this, 0);
+ compiler->EmitCallsiteMetadata(token_pos(), DeoptId::kNone,
+ RawPcDescriptors::kOther, locs(),
+ extended_env);
+ } else {
+ BoxAllocationSlowPath::Allocate(compiler, this, compiler->mint_class(),
+ out, temp);
+ }
+ }
__ StoreToOffset(in, out, Mint::value_offset() - kHeapObjectTag);
__ Bind(&done);
@@ -6360,6 +6458,28 @@
return locs;
}
+static Condition EmitComparisonCodeRegConstant(FlowGraphCompiler* compiler,
+ Token::Kind kind,
+ BranchLabels labels,
+ Register reg,
+ const Object& obj,
+ bool needs_number_check,
+ TokenPosition token_pos,
+ intptr_t deopt_id) {
+ Condition orig_cond = (kind == Token::kEQ_STRICT) ? EQ : NE;
+ if (!needs_number_check && compiler::target::IsSmi(obj) &&
+ compiler::target::ToRawSmi(obj) == 0 &&
+ CanUseCbzTbzForComparison(compiler, reg, orig_cond, labels)) {
+ EmitCbzTbz(reg, compiler, orig_cond, labels);
+ return kInvalidCondition;
+ } else {
+ Condition true_condition = compiler->EmitEqualityRegConstCompare(
+ reg, obj, needs_number_check, token_pos, deopt_id);
+ return (kind != Token::kEQ_STRICT) ? NegateCondition(true_condition)
+ : true_condition;
+ }
+}
+
Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
BranchLabels labels) {
Location left = locs()->in(0);
@@ -6367,22 +6487,19 @@
ASSERT(!left.IsConstant() || !right.IsConstant());
Condition true_condition;
if (left.IsConstant()) {
- true_condition = compiler->EmitEqualityRegConstCompare(
- right.reg(), left.constant(), needs_number_check(), token_pos(),
- deopt_id_);
+ return EmitComparisonCodeRegConstant(compiler, kind(), labels, right.reg(),
+ left.constant(), needs_number_check(),
+ token_pos(), deopt_id_);
} else if (right.IsConstant()) {
- true_condition = compiler->EmitEqualityRegConstCompare(
- left.reg(), right.constant(), needs_number_check(), token_pos(),
- deopt_id_);
+ return EmitComparisonCodeRegConstant(compiler, kind(), labels, left.reg(),
+ right.constant(), needs_number_check(),
+ token_pos(), deopt_id_);
} else {
true_condition = compiler->EmitEqualityRegRegCompare(
left.reg(), right.reg(), needs_number_check(), token_pos(), deopt_id_);
+ return (kind() != Token::kEQ_STRICT) ? NegateCondition(true_condition)
+ : true_condition;
}
- if (kind() != Token::kEQ_STRICT) {
- ASSERT(kind() == Token::kNE_STRICT);
- true_condition = NegateCondition(true_condition);
- }
- return true_condition;
}
void ComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index de51c81..0fd3634 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -791,8 +791,7 @@
bool is_nullable,
bool* is_instance) {
ASSERT(is_instance != NULL);
- // TODO(regis): Take mode into consideration.
- if (type.IsDynamicType() || type.IsObjectType() || type.IsVoidType()) {
+ if (type.IsTopType(mode)) {
*is_instance = true;
return true;
}
@@ -804,13 +803,32 @@
// Consider the compile type of the value.
const AbstractType& compile_type = *ToAbstractType();
- // The null instance is an instance of Null, of Object, and of dynamic.
+ // 'null' is an instance of Null, Object*, Object?, void, and dynamic.
+ // In addition, 'null' is an instance of Never and Object with legacy testing,
+ // or of any nullable or legacy type with nnbd testing.
+ // It is also an instance of FutureOr<T> if it is an instance of T.
// Functions that do not explicitly return a value, implicitly return null,
// except generative constructors, which return the object being constructed.
// It is therefore acceptable for void functions to return null.
if (compile_type.IsNullType()) {
- *is_instance = is_nullable || type.IsObjectType() || type.IsDynamicType() ||
- type.IsNullType() || type.IsVoidType();
+ if (mode == NNBDMode::kLegacyLib) {
+ // Using legacy testing.
+ if (!type.IsInstantiated()) {
+ return false;
+ }
+ AbstractType& type_arg = AbstractType::Handle(type.raw());
+ while (type_arg.IsFutureOr(&type_arg)) {
+ }
+ *is_instance =
+ is_nullable || type_arg.IsNullType() || type_arg.Legacy_IsTopType();
+ } else {
+ ASSERT(mode == NNBDMode::kOptedInLib);
+ // Using nnbd testing.
+ if (type.IsUndetermined()) {
+ return false;
+ }
+ *is_instance = is_nullable || type.IsNullable() || type.IsLegacy();
+ }
return true;
}
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 7535d0e..ac5f06e 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -854,9 +854,9 @@
// Build an AssertAssignable if necessary.
const AbstractType& dst_type = AbstractType::ZoneHandle(zone(), field.type());
- if (I->argument_type_checks() && !dst_type.IsTopType()) {
+ if (I->argument_type_checks() && !dst_type.IsTopType(target.nnbd_mode())) {
// Compute if we need to type check the value. Always type check if
- // not in strong mode or if at a dynamic invocation.
+ // at a dynamic invocation.
bool needs_check = true;
if (!instr->interface_target().IsNull()) {
if (field.is_covariant()) {
@@ -1095,18 +1095,31 @@
if (cls.NumTypeArguments() > 0) {
return Bool::null();
}
- // As of Dart 1.5, the Null type is a subtype of (and is more specific than)
- // any type. However, we are checking instances here and not types. The
- // null instance is only an instance of Null, Object, and dynamic.
- // TODO(regis): Consider nullability of type if mode is not kLegacy, or if
- // strong mode is enabled.
- const bool is_subtype =
- cls.IsNullClass()
- ? (type_class.IsNullClass() || type_class.IsObjectClass() ||
- type_class.IsDynamicClass())
- : Class::IsSubtypeOf(mode, cls, Object::null_type_arguments(),
- type_class, Object::null_type_arguments(),
- Heap::kOld);
+ bool is_subtype = false;
+ if (cls.IsNullClass()) {
+ // 'null' is an instance of Null, Object*, Object?, void, and dynamic.
+ // In addition, 'null' is an instance of Never and Object with legacy
+ // testing, or of any nullable or legacy type with nnbd testing.
+ // It is also an instance of FutureOr<T> if it is an instance of T.
+ if (mode == NNBDMode::kLegacyLib) {
+ // Using legacy testing.
+ ASSERT(type.IsInstantiated());
+ AbstractType& type_arg = AbstractType::Handle(type.raw());
+ while (type_arg.IsFutureOr(&type_arg)) {
+ }
+ is_subtype = type_arg.IsNullType() || type_arg.Legacy_IsTopType();
+ } else {
+ ASSERT(mode == NNBDMode::kOptedInLib);
+ // Using nnbd testing.
+ ASSERT(!type.IsUndetermined());
+ is_subtype =
+ type.IsNullable() || type.IsLegacy() || type.NNBD_IsTopType();
+ }
+ } else {
+ is_subtype = Class::IsSubtypeOf(mode, cls, Object::null_type_arguments(),
+ type_class, Object::null_type_arguments(),
+ Heap::kOld);
+ }
results->Add(cls.id());
results->Add(static_cast<intptr_t>(is_subtype));
if (prev.IsNull()) {
@@ -1136,10 +1149,6 @@
return false;
}
- if (mode != NNBDMode::kLegacyLib) {
- return false; // TODO(regis): Implement.
- }
-
// Private classes cannot be subclassed by later loaded libs.
if (!type_class.IsPrivate()) {
// In AOT mode we can't use CHA deoptimizations.
@@ -1169,7 +1178,15 @@
TypeArguments::Handle(type.arguments());
const bool is_raw_type = type_arguments.IsNull() ||
type_arguments.IsRaw(from_index, num_type_params);
- return is_raw_type;
+ if (!is_raw_type) {
+ return false;
+ }
+ }
+ if (mode == NNBDMode::kOptedInLib && !type.IsNonNullable()) {
+ // A class id check is not sufficient, since a null instance also satisfies
+ // the test against a nullable or legacy type.
+ // TODO(regis): Add a null check in addition to the class id check?
+ return false;
}
return true;
}
@@ -1188,17 +1205,33 @@
ASSERT(I->can_use_strong_mode_types());
ASSERT(Token::IsTypeTestOperator(call->token_kind()));
- if (mode != NNBDMode::kLegacyLib) {
- return false; // TODO(regis): Implement.
- }
-
- if (type.IsDynamicType() || type.IsObjectType() || !type.IsInstantiated()) {
+ // 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*, Object?, void, and dynamic.
+ // In addition, 'null' is an instance of Never and Object with legacy testing,
+ // or of any nullable or legacy type with nnbd testing.
+ // It is also an instance of FutureOr<T> if it is an instance of T.
+ if (mode == NNBDMode::kLegacyLib) {
+ // Using legacy testing of null instance.
+ if (type.Legacy_IsTopType() || !type.IsInstantiated()) {
+ return false; // Always true or cannot tell.
+ }
+ } else {
+ ASSERT(mode == NNBDMode::kOptedInLib);
+ // Checking whether the receiver is null cannot help in an opted-in library.
+ // Indeed, its static type would have to be nullable to legally hold null.
+ // For the static type to be a subtype of the tested type, the tested type
+ // has to be nullable as well, in which case it makes no difference if the
+ // receiver is null or not.
return false;
}
const intptr_t receiver_index = call->FirstArgIndex();
Value* left_value = call->ArgumentValueAt(receiver_index);
+ // 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(mode, type)) {
Definition* replacement = new (Z) StrictCompareInstr(
call->token_pos(),
@@ -1246,8 +1279,6 @@
Smi::Cast(call->ArgumentAt(4)->AsConstant()->value()).Value());
}
- // TODO(regis): Revisit call_specializer for NNBD.
-
if (I->can_use_strong_mode_types() &&
TryOptimizeInstanceOfUsingStaticTypes(nnbd_mode, call, type)) {
return;
@@ -1281,8 +1312,7 @@
Z, InstanceOfAsBool(nnbd_mode, unary_checks, type, results));
if (as_bool.IsNull() || FLAG_precompiled_mode) {
if (results->length() == number_of_checks * 2) {
- const bool can_deopt =
- SpecializeTestCidsForNumericTypes(nnbd_mode, results, type);
+ const bool can_deopt = SpecializeTestCidsForNumericTypes(results, type);
if (can_deopt &&
!speculative_policy_->IsAllowedForInlining(call->deopt_id())) {
// Guard against repeated speculative inlining.
@@ -1429,7 +1459,6 @@
}
bool CallSpecializer::SpecializeTestCidsForNumericTypes(
- NNBDMode mode,
ZoneGrowableArray<intptr_t>* results,
const AbstractType& type) {
ASSERT(results->length() >= 2); // At least on entry.
@@ -1437,11 +1466,10 @@
if ((*results)[0] != kSmiCid) {
const Class& smi_class = Class::Handle(class_table.At(kSmiCid));
const Class& type_class = Class::Handle(type.type_class());
- // TODO(regis): Consider nullability of type if mode is not kLegacy, or if
- // strong mode is enabled.
+ // When testing '42 is type', the nullability of type is irrelevant.
const bool smi_is_subtype = Class::IsSubtypeOf(
- mode, smi_class, Object::null_type_arguments(), type_class,
- Object::null_type_arguments(), Heap::kOld);
+ NNBDMode::kLegacyLib, smi_class, Object::null_type_arguments(),
+ type_class, Object::null_type_arguments(), Heap::kOld);
results->Add((*results)[results->length() - 2]);
results->Add((*results)[results->length() - 2]);
for (intptr_t i = results->length() - 3; i > 1; --i) {
@@ -1565,12 +1593,12 @@
value_type = call->ArgumentAt(receiver_index + 2)->Type();
}
- // TODO(regis): Revisit for NNBD support.
-
auto& type_class = Class::Handle(zone_);
#define TRY_INLINE(iface, member_name, type, cid) \
if (!member_name.IsNull()) { \
- if (receiver_type->IsAssignableTo(NNBDMode::kLegacyLib, member_name)) { \
+ const NNBDMode mode = \
+ member_name.IsLegacy() ? NNBDMode::kLegacyLib : NNBDMode::kOptedInLib; \
+ if (receiver_type->IsAssignableTo(mode, member_name)) { \
if (is_length_getter) { \
type_class = member_name.type_class(); \
ReplaceWithLengthGetter(call); \
@@ -1580,7 +1608,7 @@
ReplaceWithIndexGet(call, cid); \
} else { \
if (!index_type->IsNullableInt()) return; \
- if (!value_type->IsAssignableTo(NNBDMode::kLegacyLib, type)) return; \
+ if (!value_type->IsAssignableTo(mode, type)) return; \
type_class = member_name.type_class(); \
ReplaceWithIndexSet(call, cid); \
} \
diff --git a/runtime/vm/compiler/call_specializer.h b/runtime/vm/compiler/call_specializer.h
index 80f4afe..940243d 100644
--- a/runtime/vm/compiler/call_specializer.h
+++ b/runtime/vm/compiler/call_specializer.h
@@ -168,7 +168,6 @@
// necessary for common number-related type tests. Unconditionally adds an
// entry for the Smi type to the start of the array.
static bool SpecializeTestCidsForNumericTypes(
- NNBDMode mode,
ZoneGrowableArray<intptr_t>* results,
const AbstractType& type);
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 7c9a9db..f14cd8b 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -384,6 +384,7 @@
checks.Add(function);
checks.Add(default_args);
+ const NNBDMode nnbd_mode = function.nnbd_mode();
const auto& type_params =
TypeArguments::Handle(Z, function.type_parameters());
if (!type_params.IsNull()) {
@@ -392,7 +393,7 @@
for (intptr_t i = 0, n = type_params.Length(); i < n; ++i) {
type_param ^= type_params.TypeAt(i);
bound = type_param.bound();
- if (!bound.IsTopType() && !type_param.IsGenericCovariantImpl()) {
+ if (!bound.IsTopType(nnbd_mode) && !type_param.IsGenericCovariantImpl()) {
name = type_param.name();
ASSERT(type_param.IsFinalized());
check = ParameterTypeCheck::New();
@@ -418,7 +419,7 @@
const bool has_optional_parameters = function.HasOptionalParameters();
for (intptr_t i = function.NumImplicitParameters(); i < num_params; ++i) {
type = function.ParameterTypeAt(i);
- if (!type.IsTopType() && !is_generic_covariant_impl.Contains(i) &&
+ if (!type.IsTopType(nnbd_mode) && !is_generic_covariant_impl.Contains(i) &&
!is_covariant.Contains(i)) {
name = function.ParameterNameAt(i);
intptr_t index;
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index b4f6ad2..a57fa3c 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -3572,9 +3572,8 @@
const NNBDMode nnbd_mode = parsed_function()->function().nnbd_mode();
// The VM does not like an instanceOf call with a dynamic type. We need to
- // special case this situation by detecting a top type (using non-nullable
- // semantics which is safe in all cases).
- if (type.NNBD_IsTopType()) {
+ // special case this situation by detecting a top type.
+ if (type.IsTopType(nnbd_mode)) {
// Evaluate the expression on the left but ignore its result.
instructions += Drop();
@@ -3623,7 +3622,8 @@
Fragment instructions = BuildExpression(); // read operand.
const AbstractType& type = T.BuildType(); // read type.
- if (type.IsInstantiated() && type.IsTopType()) {
+ const NNBDMode nnbd_mode = parsed_function()->function().nnbd_mode();
+ if (type.IsInstantiated() && type.IsTopType(nnbd_mode)) {
// We already evaluated the operand on the left and just leave it there as
// the result of the `obj as dynamic` expression.
} else {
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index c7afab66..67af895 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -1701,11 +1701,14 @@
String& name = String::Handle(Z);
AbstractType& bound = AbstractType::Handle(Z);
Fragment check_bounds;
+ const NNBDMode nnbd_mode = forwarding_target != nullptr
+ ? forwarding_target->nnbd_mode()
+ : dart_function.nnbd_mode();
for (intptr_t i = 0; i < num_type_params; ++i) {
type_param ^= type_parameters.TypeAt(i);
bound = type_param.bound();
- if (bound.IsTopType()) {
+ if (bound.IsTopType(nnbd_mode)) {
continue;
}
@@ -1762,7 +1765,7 @@
&AbstractType::ZoneHandle(Z, forwarding_target->ParameterTypeAt(i));
}
- if (target_type->IsTopType()) continue;
+ if (target_type->IsTopType(nnbd_mode)) continue;
const bool is_covariant = param->is_explicit_covariant_parameter();
Fragment* checks = is_covariant ? explicit_checks : implicit_checks;
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 7c491dd..0af2249 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -1162,12 +1162,15 @@
// Called for allocation of Mint.
void StubCodeCompiler::GenerateAllocateMintWithFPURegsStub(
Assembler* assembler) {
- Label slow_case;
- __ TryAllocate(compiler::MintClass(), &slow_case, /*instance_reg=*/R0,
- /*temp_reg=*/R1);
- __ Ret();
+ // For test purpose call allocation stub without inline allocation attempt.
+ if (!FLAG_use_slow_path) {
+ Label slow_case;
+ __ TryAllocate(compiler::MintClass(), &slow_case, /*instance_reg=*/R0,
+ /*temp_reg=*/R1);
+ __ Ret();
- __ Bind(&slow_case);
+ __ Bind(&slow_case);
+ }
GenerateSharedStub(assembler, /*save_fpu_registers=*/true,
&kAllocateMintRuntimeEntry,
target::Thread::allocate_mint_with_fpu_regs_stub_offset(),
@@ -1178,12 +1181,15 @@
// Called for allocation of Mint.
void StubCodeCompiler::GenerateAllocateMintWithoutFPURegsStub(
Assembler* assembler) {
- Label slow_case;
- __ TryAllocate(compiler::MintClass(), &slow_case, /*instance_reg=*/R0,
- /*temp_reg=*/R1);
- __ Ret();
+ // For test purpose call allocation stub without inline allocation attempt.
+ if (!FLAG_use_slow_path) {
+ Label slow_case;
+ __ TryAllocate(compiler::MintClass(), &slow_case, /*instance_reg=*/R0,
+ /*temp_reg=*/R1);
+ __ Ret();
- __ Bind(&slow_case);
+ __ Bind(&slow_case);
+ }
GenerateSharedStub(
assembler, /*save_fpu_registers=*/false, &kAllocateMintRuntimeEntry,
target::Thread::allocate_mint_without_fpu_regs_stub_offset(),
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 45a8ef7..a1162b8 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -180,7 +180,8 @@
bool save_fpu_registers,
const RuntimeEntry* target,
intptr_t self_code_stub_offset_from_thread,
- bool allow_return) {
+ bool allow_return,
+ bool store_runtime_result_in_r0 = false) {
// We want the saved registers to appear like part of the caller's frame, so
// we push them before calling EnterStubFrame.
RegisterSet all_registers;
@@ -192,12 +193,28 @@
__ PushRegisters(all_registers);
__ ldr(CODE_REG, Address(THR, self_code_stub_offset_from_thread));
__ EnterStubFrame();
+ if (store_runtime_result_in_r0) {
+ ASSERT(all_registers.ContainsRegister(R0));
+ ASSERT(allow_return);
+
+ // Push an even value so it will not be seen as a pointer
+ __ Push(LR);
+ }
__ CallRuntime(*target, /*argument_count=*/0);
+
+ if (store_runtime_result_in_r0) {
+ __ Pop(R0);
+ }
if (!allow_return) {
__ Breakpoint();
return;
}
__ LeaveStubFrame();
+ if (store_runtime_result_in_r0) {
+ // Stores the runtime result in stack where R0 was pushed ( R0 is the very
+ // last register to be pushed by __ PushRegisters(all_registers) )
+ __ str(R0, Address(SP));
+ }
__ PopRegisters(all_registers);
__ Pop(LR);
__ ret(LR);
@@ -1235,12 +1252,38 @@
void StubCodeCompiler::GenerateAllocateMintWithFPURegsStub(
Assembler* assembler) {
- __ Stop("Unimplemented");
+ // For test purpose call allocation stub without inline allocation attempt.
+ if (!FLAG_use_slow_path) {
+ Label slow_case;
+ __ TryAllocate(compiler::MintClass(), &slow_case, /*instance_reg=*/R0,
+ /*temp_reg=*/R1);
+ __ Ret();
+
+ __ Bind(&slow_case);
+ }
+ GenerateSharedStub(assembler, /*save_fpu_registers=*/true,
+ &kAllocateMintRuntimeEntry,
+ target::Thread::allocate_mint_with_fpu_regs_stub_offset(),
+ /*allow_return=*/true,
+ /*store_runtime_result_in_r0=*/true);
}
void StubCodeCompiler::GenerateAllocateMintWithoutFPURegsStub(
Assembler* assembler) {
- __ Stop("Unimplemented");
+ // For test purpose call allocation stub without inline allocation attempt.
+ if (!FLAG_use_slow_path) {
+ Label slow_case;
+ __ TryAllocate(compiler::MintClass(), &slow_case, /*instance_reg=*/R0,
+ /*temp_reg=*/R1);
+ __ Ret();
+
+ __ Bind(&slow_case);
+ }
+ GenerateSharedStub(
+ assembler, /*save_fpu_registers=*/false, &kAllocateMintRuntimeEntry,
+ target::Thread::allocate_mint_without_fpu_regs_stub_offset(),
+ /*allow_return=*/true,
+ /*store_runtime_result_in_r0=*/true);
}
// Called when invoking Dart code from C++ (VM code).
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index d9317ad..6c701a1 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -6142,8 +6142,7 @@
StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
callback, debug_callback_data);
- Elf* elf =
- generate_debug ? new (Z) Elf(Z, nullptr, strip, &debug_stream) : nullptr;
+ Elf* elf = generate_debug ? new (Z) Elf(Z, &debug_stream) : nullptr;
AssemblyImageWriter image_writer(T, callback, callback_data, strip, elf);
uint8_t* vm_snapshot_data_buffer = NULL;
@@ -6217,12 +6216,11 @@
StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
callback, debug_callback_data);
- Elf* elf = new (Z)
- Elf(Z, &elf_stream, strip, generate_debug ? &debug_stream : nullptr);
- Dwarf* dwarf = nullptr;
- if (!strip || generate_debug) {
- dwarf = new (Z) Dwarf(Z, nullptr, elf);
- }
+ Elf* elf = new (Z) Elf(Z, &elf_stream);
+ Dwarf* elf_dwarf = strip ? nullptr : new (Z) Dwarf(Z, nullptr, elf);
+ Elf* debug_elf = generate_debug ? new (Z) Elf(Z, &debug_stream) : nullptr;
+ Dwarf* debug_dwarf =
+ generate_debug ? new (Z) Dwarf(Z, nullptr, debug_elf) : nullptr;
// Note that the BSS section must come first because it cannot be placed in
// between any two non-writable segments, due to a bug in Jelly Bean's ELF
@@ -6231,11 +6229,11 @@
elf->AddBSSData("_kDartBSSData", sizeof(compiler::target::uword));
BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions_buffer,
- ApiReallocate, kInitialSize, bss_base, elf,
- dwarf);
+ ApiReallocate, kInitialSize, debug_dwarf,
+ bss_base, elf, elf_dwarf);
BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions_buffer,
- ApiReallocate, kInitialSize, bss_base,
- elf, dwarf);
+ ApiReallocate, kInitialSize, debug_dwarf,
+ bss_base, elf, elf_dwarf);
FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
&isolate_snapshot_data_buffer, ApiReallocate,
&vm_image_writer, &isolate_image_writer);
@@ -6245,12 +6243,17 @@
writer.VmIsolateSnapshotSize());
elf->AddROData("_kDartIsolateSnapshotData", isolate_snapshot_data_buffer,
writer.IsolateSnapshotSize());
- if (dwarf != nullptr) {
+
+ if (elf_dwarf != nullptr) {
// TODO(rmacnak): Generate .debug_frame / .eh_frame / .arm.exidx to
// provide unwinding information.
- dwarf->Write();
+ elf_dwarf->Write();
}
elf->Finalize();
+ if (generate_debug) {
+ debug_dwarf->Write();
+ debug_elf->Finalize();
+ }
return Api::Success();
#endif
@@ -6300,16 +6303,14 @@
Elf* elf = nullptr;
Dwarf* dwarf = nullptr;
if (generate_debug) {
- elf = new (Z) Elf(Z, nullptr, /*strip=*/false, &debug_stream);
+ elf = new (Z) Elf(Z, &debug_stream);
dwarf = new (Z) Dwarf(Z, nullptr, elf);
}
BlobImageWriter vm_image_writer(T, vm_snapshot_instructions_buffer,
- ApiReallocate, kInitialSize, /*bss_base=*/0,
- elf, dwarf);
+ ApiReallocate, kInitialSize, dwarf);
BlobImageWriter isolate_image_writer(T, isolate_snapshot_instructions_buffer,
- ApiReallocate, kInitialSize,
- /*bss_base=*/0, elf, dwarf);
+ ApiReallocate, kInitialSize, dwarf);
FullSnapshotWriter writer(Snapshot::kFullAOT, vm_snapshot_data_buffer,
isolate_snapshot_data_buffer, ApiReallocate,
&vm_image_writer, &isolate_image_writer);
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index dbf3db6..60e9b62 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -7,6 +7,7 @@
#include "platform/elf.h"
#include "platform/text_buffer.h"
#include "vm/cpu.h"
+#include "vm/hash_map.h"
#include "vm/thread.h"
namespace dart {
@@ -29,96 +30,335 @@
static const intptr_t kElfSymbolHashTableEntrySize = 4;
#endif
+#define DEFINE_LINEAR_FIELD_METHODS(name, type, init) \
+ type name() const { \
+ ASSERT(name##_ != init); \
+ return name##_; \
+ } \
+ void set_##name(type value) { \
+ ASSERT(name##_ == init); \
+ name##_ = value; \
+ }
+
+#define DEFINE_LINEAR_FIELD(name, type, init) type name##_ = init;
+
class Section : public ZoneAllocated {
public:
- Section() {}
+ Section(intptr_t type,
+ intptr_t segment_type,
+ bool allocate,
+ bool executable,
+ bool writable,
+ intptr_t alignment = 1)
+ : section_type(type),
+ section_flags(EncodeSectionFlags(allocate, executable, writable)),
+ alignment(allocate ? SegmentAlignment(alignment) : alignment),
+ segment_type(segment_type),
+ segment_flags(EncodeSegmentFlags(allocate, executable, writable)),
+ // Non-segments will never have a memory offset, here represented by 0.
+ memory_offset_(allocate ? -1 : 0) {
+ // Only the reserved section (type 0) should have an alignment of 0.
+ ASSERT(type == 0 || alignment > 0);
+ }
+
+ // The constructor that most subclasses will use.
+ Section(intptr_t type,
+ bool allocate,
+ bool executable,
+ bool writable,
+ intptr_t alignment = 1)
+ : Section(type,
+ /*segment_type=*/allocate ? elf::PT_LOAD : 0,
+ allocate,
+ executable,
+ writable,
+ alignment) {}
virtual ~Section() {}
- virtual void Write(StreamingWriteStream* stream) = 0;
// Linker view.
- intptr_t section_name = -1; // Index into shstrtab_.
- intptr_t section_type = 0;
- intptr_t section_flags = 0;
- intptr_t section_index = -1;
+ const intptr_t section_type;
+ const intptr_t section_flags;
+ const intptr_t alignment;
+
+ // These are fields that only are not set for most kinds of sections and so we
+ // set them to a reasonable default.
intptr_t section_link = elf::SHN_UNDEF;
intptr_t section_info = 0;
intptr_t section_entry_size = 0;
- intptr_t file_size = 0;
- intptr_t file_offset = -1;
- intptr_t alignment = 1;
+#define FOR_EACH_SECTION_LINEAR_FIELD(M) \
+ M(section_name, intptr_t, -1) \
+ M(section_index, intptr_t, -1) \
+ M(file_offset, intptr_t, -1)
+
+ FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
+
+ virtual intptr_t FileSize() = 0;
// Loader view.
- intptr_t segment_type = -1;
- intptr_t segment_flags = 0;
- intptr_t memory_size = 0;
- intptr_t memory_offset = -1;
+ const intptr_t segment_type;
+ const intptr_t segment_flags;
- enum OutputType {
- kMainOutput,
- kDebugOutput,
- kAllOutput,
- };
+#define FOR_EACH_SEGMENT_LINEAR_FIELD(M) M(memory_offset, intptr_t, -1)
- // When this section should be output, if we are stripping and/or splitting
- // debugging information. Only a few sections are not part of the main
- // (non-debugging) output, so we use kMainOutput as the default value.
- OutputType output_type = kMainOutput;
+ FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
+
+ virtual intptr_t MemorySize() = 0;
+
+ // Other methods.
+ virtual void Write(Elf* stream) = 0;
+
+ void WriteSegmentEntry(Elf* stream, bool dynamic = false) {
+ // This should never be used on either the reserved 0-filled section or
+ // on sections without a segment.
+ ASSERT(MemorySize() > 0);
+ // dynamic should only be true if this section is the dynamic table.
+ ASSERT(!dynamic || section_type == elf::SHT_DYNAMIC);
+#if defined(TARGET_ARCH_IS_32_BIT)
+ stream->WriteWord(dynamic ? elf::PT_DYNAMIC : segment_type);
+ stream->WriteOff(file_offset());
+ stream->WriteAddr(memory_offset()); // Virtual address.
+ stream->WriteAddr(memory_offset()); // Physical address, not used.
+ stream->WriteWord(FileSize());
+ stream->WriteWord(MemorySize());
+ stream->WriteWord(segment_flags);
+ stream->WriteWord(alignment);
+#else
+ stream->WriteWord(dynamic ? elf::PT_DYNAMIC : segment_type);
+ stream->WriteWord(segment_flags);
+ stream->WriteOff(file_offset());
+ stream->WriteAddr(memory_offset()); // Virtual address.
+ stream->WriteAddr(memory_offset()); // Physical address, not used.
+ stream->WriteXWord(FileSize());
+ stream->WriteXWord(MemorySize());
+ stream->WriteXWord(alignment);
+#endif
+ }
+
+ void WriteSectionEntry(Elf* stream) {
+#if defined(TARGET_ARCH_IS_32_BIT)
+ stream->WriteWord(section_name());
+ stream->WriteWord(section_type);
+ stream->WriteWord(section_flags);
+ stream->WriteAddr(memory_offset());
+ stream->WriteOff(file_offset());
+ stream->WriteWord(FileSize()); // Has different meaning for BSS.
+ stream->WriteWord(section_link);
+ stream->WriteWord(section_info);
+ stream->WriteWord(alignment);
+ stream->WriteWord(section_entry_size);
+#else
+ stream->WriteWord(section_name());
+ stream->WriteWord(section_type);
+ stream->WriteXWord(section_flags);
+ stream->WriteAddr(memory_offset());
+ stream->WriteOff(file_offset());
+ stream->WriteXWord(FileSize()); // Has different meaning for BSS.
+ stream->WriteWord(section_link);
+ stream->WriteWord(section_info);
+ stream->WriteXWord(alignment);
+ stream->WriteXWord(section_entry_size);
+#endif
+ }
+
+ private:
+ static intptr_t EncodeSectionFlags(bool allocate,
+ bool executable,
+ bool writable) {
+ if (!allocate) return 0;
+ intptr_t flags = elf::SHF_ALLOC;
+ if (executable) flags |= elf::SHF_EXECINSTR;
+ if (writable) flags |= elf::SHF_WRITE;
+ return flags;
+ }
+
+ static intptr_t EncodeSegmentFlags(bool allocate,
+ bool executable,
+ bool writable) {
+ if (!allocate) return 0;
+ intptr_t flags = elf::PF_R;
+ if (executable) flags |= elf::PF_X;
+ if (writable) flags |= elf::PF_W;
+ return flags;
+ }
+
+ static intptr_t SegmentAlignment(intptr_t alignment) {
+ return alignment < Elf::kPageSize ? Elf::kPageSize : alignment;
+ }
+
+ FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
+ FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
+
+#undef FOR_EACH_SECTION_LINEAR_FIELD
+#undef FOR_EACH_SEGMENT_LINEAR_FIELD
};
-class ProgramBits : public Section {
+#undef DEFINE_LINEAR_FIELD
+#undef DEFINE_LINEAR_FIELD_METHODS
+
+// Represents the first entry in the section table, which should only contain
+// zero values. Only used for WriteSectionEntry and should never actually appear
+// in sections_.
+class ReservedSection : public Section {
+ public:
+ ReservedSection()
+ : Section(/*type=*/0,
+ /*allocate=*/false,
+ /*executable=*/false,
+ /*writable=*/false,
+ /*alignment=*/0) {
+ set_section_name(0);
+ set_section_index(0);
+ set_file_offset(0);
+ }
+
+ intptr_t FileSize() { return 0; }
+ intptr_t MemorySize() { return 0; }
+ void Write(Elf* stream) { UNREACHABLE(); }
+};
+
+class BlobSection : public Section {
+ public:
+ BlobSection(intptr_t type,
+ intptr_t segment_type,
+ bool allocate,
+ bool executable,
+ bool writable,
+ intptr_t filesz,
+ intptr_t memsz,
+ int alignment = 1)
+ : Section(type, segment_type, allocate, executable, writable, alignment),
+ file_size_(filesz),
+ memory_size_(allocate ? memsz : 0) {}
+
+ BlobSection(intptr_t type,
+ bool allocate,
+ bool executable,
+ bool writable,
+ intptr_t filesz,
+ intptr_t memsz,
+ int alignment = 1)
+ : BlobSection(type,
+ /*segment_type=*/allocate ? elf::PT_LOAD : 0,
+ allocate,
+ executable,
+ writable,
+ filesz,
+ memsz,
+ alignment) {}
+
+ intptr_t FileSize() { return file_size_; }
+ intptr_t MemorySize() { return memory_size_; }
+
+ virtual void Write(Elf* stream) = 0;
+
+ private:
+ const intptr_t file_size_;
+ const intptr_t memory_size_;
+};
+
+// A section for representing the program header segment in the program header
+// table. Only used for WriteSegmentEntry.
+class ProgramTable : public BlobSection {
+ public:
+ ProgramTable(intptr_t offset, intptr_t size)
+ : BlobSection(/*type=*/0,
+ /*segment_type=*/elf::PT_PHDR,
+ /*allocate=*/true,
+ /*executable=*/false,
+ /*writable=*/false,
+ /*filesz=*/size,
+ /*memsz=*/size) {
+ set_file_offset(offset);
+ set_memory_offset(offset);
+ }
+
+ // This should never actually be added to sections_ or segments_.
+ void Write(Elf* stream) { UNREACHABLE(); }
+};
+
+// A section for representing the program header table load segment in the
+// program header table. Only used for WriteSegmentEntry.
+class ProgramTableLoad : public BlobSection {
+ public:
+ // The Android dynamic linker in Jelly Bean incorrectly assumes that all
+ // non-writable segments are continguous. Since the BSS segment comes directly
+ // after the program header segment, we must make this segment writable so
+ // later non-writable segments does not cause the BSS to be also marked as
+ // read-only.
+ //
+ // The bug is here:
+ // https://github.com/aosp-mirror/platform_bionic/blob/94963af28e445384e19775a838a29e6a71708179/linker/linker.c#L1991-L2001
+ explicit ProgramTableLoad(intptr_t size)
+ : BlobSection(/*type=*/0,
+ /*allocate=*/true,
+ /*executable=*/false,
+ /*writable=*/true,
+ /*filesz=*/size,
+ /*memsz=*/size) {
+ set_file_offset(0);
+ set_memory_offset(0);
+ }
+
+ // This should never actually be added to sections_ or segments_.
+ void Write(Elf* stream) { UNREACHABLE(); }
+};
+
+class ProgramBits : public BlobSection {
public:
ProgramBits(bool allocate,
bool executable,
bool writable,
const uint8_t* bytes,
intptr_t filesz,
- intptr_t memsz = -1) {
- if (memsz == -1) memsz = filesz;
+ intptr_t memsz = -1)
+ : BlobSection(elf::SHT_PROGBITS,
+ allocate,
+ executable,
+ writable,
+ filesz,
+ memsz != -1 ? memsz : filesz),
+ bytes_(ASSERT_NOTNULL(bytes)) {}
- section_type = elf::SHT_PROGBITS;
- if (allocate) {
- section_flags = elf::SHF_ALLOC;
- if (executable) section_flags |= elf::SHF_EXECINSTR;
- if (writable) section_flags |= elf::SHF_WRITE;
-
- segment_type = elf::PT_LOAD;
- segment_flags = elf::PF_R;
- if (executable) segment_flags |= elf::PF_X;
- if (writable) segment_flags |= elf::PF_W;
- }
-
- bytes_ = bytes;
- file_size = filesz;
- memory_size = memsz;
- }
-
- void Write(StreamingWriteStream* stream) {
- if (bytes_ != nullptr) {
- Elf::WriteBytes(stream, bytes_, file_size);
- }
- }
+ void Write(Elf* stream) { stream->WriteBytes(bytes_, FileSize()); }
const uint8_t* bytes_;
};
+class NoBits : public BlobSection {
+ public:
+ NoBits(bool allocate, bool executable, bool writable, intptr_t memsz)
+ : BlobSection(elf::SHT_NOBITS,
+ allocate,
+ executable,
+ writable,
+ /*filesz=*/0,
+ memsz) {}
+
+ void Write(Elf* stream) {}
+};
+
class StringTable : public Section {
public:
- explicit StringTable(bool dynamic) : text_(128), text_indices_() {
- section_type = elf::SHT_STRTAB;
- if (dynamic) {
- section_flags = elf::SHF_ALLOC;
- segment_type = elf::PT_LOAD;
- segment_flags = elf::PF_R;
- } else {
- section_flags = 0;
- memory_offset = 0; // No segments for static tables.
- }
-
+ explicit StringTable(bool allocate)
+ : Section(elf::SHT_STRTAB,
+ allocate,
+ /*executable=*/false,
+ /*writable=*/false),
+ dynamic_(allocate),
+ text_(128),
+ text_indices_() {
text_.AddChar('\0');
text_indices_.Insert({"", 1});
- memory_size = file_size = text_.length();
+ }
+
+ intptr_t FileSize() { return text_.length(); }
+ intptr_t MemorySize() { return dynamic_ ? FileSize() : 0; }
+
+ void Write(Elf* stream) {
+ stream->WriteBytes(reinterpret_cast<const uint8_t*>(text_.buf()),
+ text_.length());
}
intptr_t AddString(const char* str) {
@@ -127,20 +367,10 @@
text_.AddString(str);
text_.AddChar('\0');
text_indices_.Insert({str, offset + 1});
- memory_size = file_size = text_.length();
return offset;
}
- const char* GetString(intptr_t index) {
- ASSERT(index >= 0 && index < text_.length());
- return text_.buf() + index;
- }
-
- void Write(StreamingWriteStream* stream) {
- Elf::WriteBytes(stream, reinterpret_cast<const uint8_t*>(text_.buf()),
- text_.length());
- }
-
+ const bool dynamic_;
TextBuffer text_;
// To avoid kNoValue for intptr_t (0), we store an index n as n + 1.
CStringMap<intptr_t> text_indices_;
@@ -148,97 +378,84 @@
class Symbol : public ZoneAllocated {
public:
- const char* cstr;
- intptr_t name;
- intptr_t info;
- intptr_t section;
- intptr_t offset;
- intptr_t size;
+ Symbol(const char* cstr,
+ intptr_t name,
+ intptr_t info,
+ intptr_t section,
+ intptr_t offset,
+ intptr_t size)
+ : cstr_(cstr),
+ name_index_(name),
+ info_(info),
+ section_index_(section),
+ offset_(offset),
+ size_(size) {}
+
+ void Write(Elf* stream) const {
+ stream->WriteWord(name_index_);
+#if defined(TARGET_ARCH_IS_32_BIT)
+ stream->WriteAddr(offset_);
+ stream->WriteWord(size_);
+ stream->WriteByte(info_);
+ stream->WriteByte(0);
+ stream->WriteHalf(section_index_);
+#else
+ stream->WriteByte(info_);
+ stream->WriteByte(0);
+ stream->WriteHalf(section_index_);
+ stream->WriteAddr(offset_);
+ stream->WriteXWord(size_);
+#endif
+ }
+
+ private:
+ friend class SymbolHashTable; // For cstr_ access.
+
+ const char* cstr_;
+ intptr_t name_index_;
+ intptr_t info_;
+ intptr_t section_index_;
+ intptr_t offset_;
+ intptr_t size_;
};
class SymbolTable : public Section {
public:
- explicit SymbolTable(bool dynamic) {
- if (dynamic) {
- section_type = elf::SHT_DYNSYM;
- section_flags = elf::SHF_ALLOC;
- segment_type = elf::PT_LOAD;
- segment_flags = elf::PF_R;
- } else {
- // No need to load the static symbol table at runtime since it's ignored
- // by the dynamic linker.
- section_type = elf::SHT_SYMTAB;
- section_flags = 0;
- memory_offset = 0; // No segments for static tables.
- alignment = compiler::target::kWordSize;
- }
-
+ explicit SymbolTable(bool dynamic)
+ : Section(dynamic ? elf::SHT_DYNSYM : elf::SHT_SYMTAB,
+ dynamic,
+ /*executable=*/false,
+ /*writable=*/false,
+ compiler::target::kWordSize),
+ dynamic_(dynamic),
+ reserved_("", 0, 0, 0, 0, 0) {
section_entry_size = kElfSymbolTableEntrySize;
- section_info = 0;
- AddSymbol(nullptr);
- }
-
- void AddSymbol(Symbol* symbol) {
- // Adjust section_info to contain the count of local symbols, including the
- // reserved first entry (represented by the nullptr value).
- if (symbol == nullptr || ((symbol->info >> 4) == elf::STB_LOCAL)) {
- section_info += 1;
- }
- symbols_.Add(symbol);
- memory_size += kElfSymbolTableEntrySize;
- file_size += kElfSymbolTableEntrySize;
- }
-
- void Write(StreamingWriteStream* stream) {
// The first symbol table entry is reserved and must be all zeros.
- {
- const intptr_t start = stream->position();
-#if defined(TARGET_ARCH_IS_32_BIT)
- Elf::WriteWord(stream, 0);
- Elf::WriteAddr(stream, 0);
- Elf::WriteWord(stream, 0);
- Elf::WriteByte(stream, 0);
- Elf::WriteByte(stream, 0);
- Elf::WriteHalf(stream, 0);
-#else
- Elf::WriteWord(stream, 0);
- Elf::WriteByte(stream, 0);
- Elf::WriteByte(stream, 0);
- Elf::WriteHalf(stream, 0);
- Elf::WriteAddr(stream, 0);
- Elf::WriteXWord(stream, 0);
-#endif
- const intptr_t end = stream->position();
- ASSERT((end - start) == kElfSymbolTableEntrySize);
- }
+ symbols_.Add(&reserved_);
+ section_info = 1; // One "local" symbol, the reserved first entry.
+ }
- for (intptr_t i = 1; i < symbols_.length(); i++) {
- Symbol* symbol = symbols_[i];
+ intptr_t FileSize() { return Length() * kElfSymbolTableEntrySize; }
+ intptr_t MemorySize() { return dynamic_ ? FileSize() : 0; }
+
+ void Write(Elf* stream) {
+ for (intptr_t i = 0; i < Length(); i++) {
+ auto const symbol = At(i);
const intptr_t start = stream->position();
-#if defined(TARGET_ARCH_IS_32_BIT)
- Elf::WriteWord(stream, symbol->name);
- Elf::WriteAddr(stream, symbol->offset);
- Elf::WriteWord(stream, symbol->size);
- Elf::WriteByte(stream, symbol->info);
- Elf::WriteByte(stream, 0);
- Elf::WriteHalf(stream, symbol->section);
-#else
- Elf::WriteWord(stream, symbol->name);
- Elf::WriteByte(stream, symbol->info);
- Elf::WriteByte(stream, 0);
- Elf::WriteHalf(stream, symbol->section);
- Elf::WriteAddr(stream, symbol->offset);
- Elf::WriteXWord(stream, symbol->size);
-#endif
+ symbol->Write(stream);
const intptr_t end = stream->position();
ASSERT((end - start) == kElfSymbolTableEntrySize);
}
}
- intptr_t length() const { return symbols_.length(); }
- Symbol* at(intptr_t i) const { return symbols_[i]; }
+ void AddSymbol(const Symbol* symbol) { symbols_.Add(symbol); }
+ intptr_t Length() const { return symbols_.length(); }
+ const Symbol* At(intptr_t i) const { return symbols_[i]; }
- GrowableArray<Symbol*> symbols_;
+ private:
+ const bool dynamic_;
+ const Symbol reserved_;
+ GrowableArray<const Symbol*> symbols_;
};
static uint32_t ElfHash(const unsigned char* name) {
@@ -254,46 +471,49 @@
class SymbolHashTable : public Section {
public:
- SymbolHashTable(StringTable* strtab, SymbolTable* symtab) {
- section_type = elf::SHT_HASH;
- section_flags = elf::SHF_ALLOC;
- section_link = symtab->section_index;
+ SymbolHashTable(StringTable* strtab, SymbolTable* symtab)
+ : Section(elf::SHT_HASH,
+ /*allocate=*/true,
+ /*executable=*/false,
+ /*writable=*/false,
+ compiler::target::kWordSize) {
+ section_link = symtab->section_index();
section_entry_size = kElfSymbolHashTableEntrySize;
- segment_type = elf::PT_LOAD;
- segment_flags = elf::PF_R;
- nchain_ = symtab->length();
- nbucket_ = symtab->length();
+ nchain_ = symtab->Length();
+ nbucket_ = symtab->Length();
- bucket_ = Thread::Current()->zone()->Alloc<int32_t>(nbucket_);
+ auto zone = Thread::Current()->zone();
+ bucket_ = zone->Alloc<int32_t>(nbucket_);
for (intptr_t i = 0; i < nbucket_; i++) {
bucket_[i] = elf::STN_UNDEF;
}
- chain_ = Thread::Current()->zone()->Alloc<int32_t>(nchain_);
+ chain_ = zone->Alloc<int32_t>(nchain_);
for (intptr_t i = 0; i < nchain_; i++) {
chain_[i] = elf::STN_UNDEF;
}
- for (intptr_t i = 1; i < symtab->length(); i++) {
- Symbol* symbol = symtab->at(i);
- uint32_t hash = ElfHash((const unsigned char*)symbol->cstr);
+ for (intptr_t i = 1; i < symtab->Length(); i++) {
+ auto const symbol = symtab->At(i);
+ uint32_t hash = ElfHash((const unsigned char*)symbol->cstr_);
uint32_t probe = hash % nbucket_;
chain_[i] = bucket_[probe]; // next = head
bucket_[probe] = i; // head = symbol
}
-
- memory_size = file_size = 4 * (nbucket_ + nchain_ + 2);
}
- void Write(StreamingWriteStream* stream) {
- Elf::WriteWord(stream, nbucket_);
- Elf::WriteWord(stream, nchain_);
+ intptr_t FileSize() { return 4 * (nbucket_ + nchain_ + 2); }
+ intptr_t MemorySize() { return FileSize(); }
+
+ void Write(Elf* stream) {
+ stream->WriteWord(nbucket_);
+ stream->WriteWord(nchain_);
for (intptr_t i = 0; i < nbucket_; i++) {
- Elf::WriteWord(stream, bucket_[i]);
+ stream->WriteWord(bucket_[i]);
}
for (intptr_t i = 0; i < nchain_; i++) {
- Elf::WriteWord(stream, chain_[i]);
+ stream->WriteWord(chain_[i]);
}
}
@@ -306,34 +526,35 @@
class DynamicTable : public Section {
public:
- DynamicTable(StringTable* strtab,
- SymbolTable* symtab,
- SymbolHashTable* hash) {
- section_type = elf::SHT_DYNAMIC;
- section_link = strtab->section_index;
- section_flags = elf::SHF_ALLOC | elf::SHF_WRITE;
+ DynamicTable(StringTable* strtab, SymbolTable* symtab, SymbolHashTable* hash)
+ : Section(elf::SHT_DYNAMIC,
+ /*allocate=*/true,
+ /*executable=*/false,
+ /*writable=*/true,
+ compiler::target::kWordSize) {
+ section_link = strtab->section_index();
section_entry_size = kElfDynamicTableEntrySize;
- segment_type = elf::PT_LOAD;
- segment_flags = elf::PF_R | elf::PF_W;
-
- AddEntry(elf::DT_HASH, hash->memory_offset);
- AddEntry(elf::DT_STRTAB, strtab->memory_offset);
- AddEntry(elf::DT_STRSZ, strtab->memory_size);
- AddEntry(elf::DT_SYMTAB, symtab->memory_offset);
+ AddEntry(elf::DT_HASH, hash->memory_offset());
+ AddEntry(elf::DT_STRTAB, strtab->memory_offset());
+ AddEntry(elf::DT_STRSZ, strtab->MemorySize());
+ AddEntry(elf::DT_SYMTAB, symtab->memory_offset());
AddEntry(elf::DT_SYMENT, kElfSymbolTableEntrySize);
AddEntry(elf::DT_NULL, 0);
}
- void Write(StreamingWriteStream* stream) {
+ intptr_t FileSize() { return entries_.length() * kElfDynamicTableEntrySize; }
+ intptr_t MemorySize() { return FileSize(); }
+
+ void Write(Elf* stream) {
for (intptr_t i = 0; i < entries_.length(); i++) {
const intptr_t start = stream->position();
#if defined(TARGET_ARCH_IS_32_BIT)
- Elf::WriteWord(stream, entries_[i]->tag);
- Elf::WriteAddr(stream, entries_[i]->value);
+ stream->WriteWord(entries_[i]->tag);
+ stream->WriteAddr(entries_[i]->value);
#else
- Elf::WriteXWord(stream, entries_[i]->tag);
- Elf::WriteAddr(stream, entries_[i]->value);
+ stream->WriteXWord(entries_[i]->tag);
+ stream->WriteAddr(entries_[i]->value);
#endif
const intptr_t end = stream->position();
ASSERT((end - start) == kElfDynamicTableEntrySize);
@@ -351,9 +572,6 @@
entry->tag = tag;
entry->value = value;
entries_.Add(entry);
-
- memory_size += kElfDynamicTableEntrySize;
- file_size += kElfDynamicTableEntrySize;
}
private:
@@ -369,102 +587,82 @@
static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
-Elf::Elf(Zone* zone,
- StreamingWriteStream* stream,
- bool strip,
- StreamingWriteStream* debug_stream)
- : zone_(ASSERT_NOTNULL(zone)),
- strip_(strip),
+Elf::Elf(Zone* zone, StreamingWriteStream* stream)
+ : zone_(zone),
stream_(stream),
- debug_stream_(debug_stream),
- sections_(zone, 2),
- segments_(zone, 2),
- active_sections_(zone, 2),
- output_sections_(zone, 2),
- adjusted_indices_(zone),
- file_sizes_(zone, 2),
- section_names_(zone, 2),
- section_types_(zone, 2) {
- // We should be outputting at least one file.
- ASSERT(stream_ != nullptr || debug_stream_ != nullptr);
- // Stripping the main output only makes sense if it'll be output.
- ASSERT(!strip || stream_ != nullptr);
-
+ shstrtab_(new (zone) StringTable(/*allocate=*/false)),
+ dynstrtab_(new (zone) StringTable(/*allocate=*/true)),
+ dynsym_(new (zone) SymbolTable(/*dynamic=*/true)),
+ memory_offset_(kProgramTableSegmentSize) {
// Assumed by various offset logic in this file.
- ASSERT(stream_ == nullptr || stream_->position() == 0);
- ASSERT(debug_stream_ == nullptr || debug_stream_->position() == 0);
-
- // All our strings would fit in a single page. However, we use separate
- // .shstrtab and .dynstr to work around a bug in Android's strip utility.
- shstrtab_ = new (zone_) StringTable(/*dynamic=*/false);
- shstrtab_->output_type = Section::kAllOutput;
-
- dynstrtab_ = new (zone_) StringTable(/*dynamic=*/true);
- dynsym_ = new (zone_) SymbolTable(/*dynamic=*/true);
-
- // The (non-section header) static tables are not needed in stripped output.
- strtab_ = new (zone_) StringTable(/*dynamic=*/false);
- strtab_->output_type = Section::kDebugOutput;
- symtab_ = new (zone_) SymbolTable(/*dynamic=*/false);
- symtab_->output_type = Section::kDebugOutput;
-
- // Allocate regular segments after the program table.
- memory_offset_ = kProgramTableSegmentSize;
+ ASSERT(stream_->position() == 0);
}
void Elf::AddSection(Section* section, const char* name) {
- section->section_index = NextSectionIndex();
- section->section_name = shstrtab_->AddString(name);
+ ASSERT(shstrtab_ != nullptr);
+ section->set_section_name(shstrtab_->AddString(name));
+ section->set_section_index(sections_.length() + kNumInvalidSections);
sections_.Add(section);
+ if (section->MemorySize() > 0) {
+ memory_offset_ = Utils::RoundUp(memory_offset_, section->alignment);
+ section->set_memory_offset(memory_offset_);
+ segments_.Add(section);
+ memory_offset_ += section->MemorySize();
+ memory_offset_ = Utils::RoundUp(memory_offset_, kPageSize);
+ }
}
-void Elf::AddSegment(Section* section) {
- if (section->alignment < kPageSize) {
- section->alignment = kPageSize;
- }
-
- memory_offset_ = Utils::RoundUp(memory_offset_, section->alignment);
- section->memory_offset = memory_offset_;
- memory_offset_ += section->memory_size;
- segments_.Add(section);
- memory_offset_ = Utils::RoundUp(memory_offset_, kPageSize);
+intptr_t Elf::NextMemoryOffset() const {
+ return memory_offset_;
}
intptr_t Elf::NextSectionIndex() const {
return sections_.length() + kNumInvalidSections;
}
-intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
- ProgramBits* image = new (zone_) ProgramBits(true, true, false, bytes, size);
- AddSection(image, ".text");
- AddSegment(image);
-
- Symbol* symbol = new (zone_) Symbol();
- symbol->cstr = name;
- symbol->name = dynstrtab_->AddString(name);
- symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
- symbol->section = image->section_index;
+intptr_t Elf::AddSectionSymbol(const Section* section,
+ const char* name,
+ intptr_t size) {
+ auto const name_index = dynstrtab_->AddString(name);
+ auto const info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
+ auto const section_index = section->section_index();
// For shared libraries, this is the offset from the DSO base. For static
// libraries, this is section relative.
- symbol->offset = image->memory_offset;
- symbol->size = size;
+ auto const memory_offset = section->memory_offset();
+ auto const symbol = new (zone_)
+ Symbol(name, name_index, info, section_index, memory_offset, size);
dynsym_->AddSymbol(symbol);
- return symbol->offset;
+ return memory_offset;
+}
+
+intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
+ Section* image = nullptr;
+ if (bytes != nullptr) {
+ image = new (zone_) ProgramBits(true, true, false, bytes, size);
+ } else {
+ image = new (zone_) NoBits(true, true, false, size);
+ }
+ AddSection(image, ".text");
+
+ return AddSectionSymbol(image, name, size);
}
void Elf::AddStaticSymbol(intptr_t section,
const char* name,
size_t memory_offset) {
- Symbol* symbol = new (zone_) Symbol();
- symbol->cstr = name;
- symbol->name = strtab_->AddString(name);
- symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
- symbol->section = section;
- // For shared libraries, this is the offset from the DSO base. For static
- // libraries, this is section relative.
- symbol->offset = memory_offset;
- symbol->size = 0;
+ // Lazily allocate the static string and symbol tables, as we only add static
+ // symbols in unstripped ELF files.
+ if (strtab_ == nullptr) {
+ ASSERT(symtab_ == nullptr);
+ strtab_ = new (zone_) StringTable(/* allocate= */ false);
+ symtab_ = new (zone_) SymbolTable(/*dynamic=*/false);
+ }
+
+ auto const name_index = strtab_->AddString(name);
+ auto const info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
+ Symbol* symbol = new (zone_)
+ Symbol(name, name_index, info, section, memory_offset, /*size=*/0);
symtab_->AddSymbol(symbol);
}
@@ -474,332 +672,82 @@
// file-size.
//
// Therefore we must insert zero-filled pages for the BSS.
- uint8_t* const bytes = Thread::Current()->zone()->Alloc<uint8_t>(size);
+ uint8_t* const bytes = zone_->Alloc<uint8_t>(size);
memset(bytes, 0, size);
- ProgramBits* const image = new (zone_)
- ProgramBits(true, false, true, bytes, /*filesz=*/size, /*memsz=*/size);
+ ProgramBits* const image =
+ new (zone_) ProgramBits(true, false, true, bytes, size);
AddSection(image, ".bss");
- AddSegment(image);
- Symbol* symbol = new (zone_) Symbol();
- symbol->cstr = name;
- symbol->name = dynstrtab_->AddString(name);
- symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_OBJECT;
- symbol->section = image->section_index;
- // For shared libraries, this is the offset from the DSO base. For static
- // libraries, this is section relative.
- symbol->offset = image->memory_offset;
- symbol->size = size;
- dynsym_->AddSymbol(symbol);
-
- return symbol->offset;
+ return AddSectionSymbol(image, name, size);
}
intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
+ ASSERT(bytes != nullptr);
ProgramBits* image = new (zone_) ProgramBits(true, false, false, bytes, size);
AddSection(image, ".rodata");
- AddSegment(image);
- Symbol* symbol = new (zone_) Symbol();
- symbol->cstr = name;
- symbol->name = dynstrtab_->AddString(name);
- symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_OBJECT;
- symbol->section = image->section_index;
- // For shared libraries, this is the offset from the DSO base. For static
- // libraries, this is section relative.
- symbol->offset = image->memory_offset;
- symbol->size = size;
- dynsym_->AddSymbol(symbol);
-
- return symbol->offset;
+ return AddSectionSymbol(image, name, size);
}
void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) {
+ ASSERT(bytes != nullptr);
ProgramBits* image =
new (zone_) ProgramBits(false, false, false, bytes, size);
- image->output_type = Section::kDebugOutput;
AddSection(image, name);
}
void Elf::Finalize() {
- SymbolHashTable* hash = new (zone_) SymbolHashTable(dynstrtab_, dynsym_);
-
- AddSection(hash, ".hash");
- AddSection(dynsym_, ".dynsym");
AddSection(dynstrtab_, ".dynstr");
+ AddSection(dynsym_, ".dynsym");
+ dynsym_->section_link = dynstrtab_->section_index();
- dynsym_->section_link = dynstrtab_->section_index;
- hash->section_link = dynsym_->section_index;
+ auto const hash = new (zone_) SymbolHashTable(dynstrtab_, dynsym_);
+ AddSection(hash, ".hash");
- // Finalizes memory size of string and symbol tables.
- AddSegment(hash);
- AddSegment(dynsym_);
- AddSegment(dynstrtab_);
+ if (symtab_ != nullptr) {
+ ASSERT(strtab_ != nullptr);
+ AddSection(strtab_, ".strtab");
+ AddSection(symtab_, ".symtab");
+ symtab_->section_link = strtab_->section_index();
+ }
dynamic_ = new (zone_) DynamicTable(dynstrtab_, dynsym_, hash);
AddSection(dynamic_, ".dynamic");
- AddSegment(dynamic_);
- // We only output the static symbol and string tables if they are non-empty.
- // We only need to check symtab_, since entries are added to strtab_ whenever
- // we add symbols. Here, an "empty" static symbol table only has one entry
- // (a nullptr value for the initial reserved entry).
- if (symtab_->symbols_.length() > 1) {
- AddSection(symtab_, ".symtab");
- AddSection(strtab_, ".strtab");
- symtab_->section_link = strtab_->section_index;
- }
-
- // The section header string table should come last.
AddSection(shstrtab_, ".shstrtab");
- if (debug_stream_ != nullptr) {
- PrepareDebugOutputInfo();
- WriteHeader(debug_stream_);
- WriteProgramTable(debug_stream_);
- WriteSections(debug_stream_);
- WriteSectionTable(debug_stream_);
- }
+ ComputeFileOffsets();
- if (stream_ != nullptr) {
- PrepareMainOutputInfo();
- WriteHeader(stream_);
- WriteProgramTable(stream_);
- WriteSections(stream_);
- WriteSectionTable(stream_);
- }
+ WriteHeader();
+ WriteProgramTable();
+ WriteSections();
+ WriteSectionTable();
}
-void Elf::ClearOutputInfo() {
- active_sections_.Clear();
- output_sections_.Clear();
- adjusted_indices_.Clear();
- file_sizes_.Clear();
- section_names_.Clear();
- section_types_.Clear();
+void Elf::ComputeFileOffsets() {
+ intptr_t file_offset = kElfHeaderSize;
- // These don't need to be cleared normally, but doing so in DEBUG mode
- // may help us catch issues.
-#if defined(DEBUG)
- section_table_entry_count_ = -1;
- section_table_file_offset_ = -1;
- program_table_entry_count_ = -1;
- program_table_file_offset_ = -1;
- for (auto section : sections_) {
- section->file_offset = -1;
- }
-#endif
-}
+ program_table_file_offset_ = file_offset;
+ program_table_file_size_ =
+ (segments_.length() + kNumImplicitSegments) * kElfProgramTableEntrySize;
+ file_offset += program_table_file_size_;
-intptr_t Elf::ActiveSectionsIndex(intptr_t section_index) const {
- // This assumes all invalid sections come first in the table.
- ASSERT(section_index >= kNumInvalidSections);
- return SectionTableIndex(section_index) - kNumInvalidSections;
-}
-
-intptr_t Elf::SectionTableIndex(intptr_t section_index) const {
- // This assumes all invalid sections come first in the table.
- if (section_index < kNumInvalidSections) return section_index;
- ASSERT(adjusted_indices_.HasKey(section_index));
- return adjusted_indices_.LookupValue(section_index);
-}
-
-intptr_t Elf::ProgramTableSize() const {
- ASSERT(program_table_entry_count_ >= 0);
- return program_table_entry_count_ * kElfProgramTableEntrySize;
-}
-
-intptr_t Elf::SectionTableSize() const {
- ASSERT(section_table_entry_count_ >= 0);
- return section_table_entry_count_ * kElfSectionTableEntrySize;
-}
-
-void Elf::VerifyOutputInfo() const {
-#if defined(DEBUG)
- // The section header string table should always be the last section. We can't
- // check for shstrtab_ because we recreate it to trim and reorder entries.
- ASSERT(active_sections_.Last()->section_type == elf::SHT_STRTAB);
- ASSERT(active_sections_.Last()->section_flags == 0);
- auto const shstrtab = reinterpret_cast<StringTable*>(active_sections_.Last());
-
- ASSERT(file_sizes_.length() == active_sections_.length());
- ASSERT(section_names_.length() == active_sections_.length());
- ASSERT(section_types_.length() == active_sections_.length());
- // Need this to output the section header.
- ASSERT(adjusted_indices_.HasKey(shstrtab->section_index));
- // Need this to output the dynamic section of the program table.
- ASSERT(adjusted_indices_.HasKey(dynamic_->section_index));
-
- // Perform extra checks on the Section GrowableArrays used in output
- // (segments_, active_sections_, and output_sections_), including that
- // they appear in the same order as in sections_.
- intptr_t last_index = 0;
- for (auto section : segments_) {
- ASSERT(section->file_offset != -1);
- ASSERT(section->section_index > last_index);
- last_index = section->section_index;
- auto const index = ActiveSectionsIndex(section->section_index);
- ASSERT(index >= 0 && index < active_sections_.length());
- ASSERT(file_sizes_.At(index) == 0 ||
- file_sizes_.At(index) == section->file_size);
- }
-
- last_index = 0;
- for (auto section : active_sections_) {
- ASSERT(section->file_offset != -1);
- ASSERT(section->section_index > last_index);
- last_index = section->section_index;
- auto const index = ActiveSectionsIndex(section->section_index);
- ASSERT(section_types_.At(index) == section->section_type ||
- section_types_.At(index) == elf::SHT_NOBITS);
- auto const link_index = SectionTableIndex(section->section_link);
- ASSERT(link_index >= 0 && link_index < section_table_entry_count_);
- auto const name_index = section_names_.At(index);
- ASSERT(name_index >= 0 && name_index < shstrtab->text_.length());
- // All (non-reserved) section names start with '.'.
- ASSERT(shstrtab->GetString(name_index)[0] == '.');
- }
-
- // Here, we primarily check that output_sections_ is a subset of
- // active_sections_, and thus all output sections are in the section table,
- // and that all the sections are continguous in the file modulo alignment.
- intptr_t file_offset = program_table_file_offset_ + ProgramTableSize();
- for (auto section : output_sections_) {
- auto const index = ActiveSectionsIndex(section->section_index);
+ for (intptr_t i = 0; i < sections_.length(); i++) {
+ Section* section = sections_[i];
file_offset = Utils::RoundUp(file_offset, section->alignment);
- ASSERT(section->file_offset == file_offset);
- file_offset += section->file_size;
- ASSERT(index >= 0 && index < active_sections_.length());
- }
- ASSERT(Utils::RoundUp(file_offset, kElfSectionTableAlignment) ==
- section_table_file_offset_);
-#endif
-}
-
-intptr_t Elf::PrepareDebugSection(Section* section,
- intptr_t file_offset,
- bool use_fake_info) {
- // All sections are output in the section table, even for debugging.
- active_sections_.Add(section);
- adjusted_indices_.Insert(section->section_index, section->section_index);
- if (use_fake_info) {
- // The fake offset of this section will be the aligned offset immediately
- // after the program table.
- auto const fake_offset = program_table_file_offset_ + ProgramTableSize();
- // No actual data will be output for these sections.
- section_types_.Add(elf::SHT_NOBITS);
- file_sizes_.Add(0);
- section->file_offset = Utils::RoundUp(fake_offset, section->alignment);
- return file_offset;
- }
- output_sections_.Add(section);
- section_types_.Add(section->section_type);
- file_sizes_.Add(section->file_size);
- section->file_offset = Utils::RoundUp(file_offset, section->alignment);
- return section->file_offset + section->file_size;
-}
-
-intptr_t Elf::PrepareMainSection(Section* section,
- intptr_t file_offset,
- intptr_t skipped_sections) {
- active_sections_.Add(section);
- output_sections_.Add(section);
- file_sizes_.Add(section->file_size);
- section_types_.Add(section->section_type);
- adjusted_indices_.Insert(section->section_index,
- section->section_index - skipped_sections);
- section->file_offset = Utils::RoundUp(file_offset, section->alignment);
- return section->file_offset + section->file_size;
-}
-
-StringTable* Elf::CreateSectionHeaderStringTable() {
- // If there are no dropped sections prior to adding the section header string
- // table, we can just use the current name indices and shstrtab_.
- if (active_sections_.length() == (sections_.length() - 1)) {
- for (auto section : active_sections_) {
- section_names_.Add(section->section_name);
- }
- section_names_.Add(shstrtab_->section_name);
- return shstrtab_;
- }
-
- auto ret = new (zone_) StringTable(/*allocate=*/false);
- // Fill fields set outside of methods in Section and its subclasses.
- ret->section_name = shstrtab_->section_name;
- ret->section_index = shstrtab_->section_index;
- ret->output_type = Section::kAllOutput;
-
- for (auto section : active_sections_) {
- auto const cstr = shstrtab_->GetString(section->section_name);
- section_names_.Add(ret->AddString(cstr));
- }
- // Now add the name for the section header string table itself.
- section_names_.Add(ret->AddString(shstrtab_->GetString(ret->section_name)));
- return ret;
-}
-
-Section* Elf::AdjustForActiveSections(Section* section) {
- // Possibly trim shstrtab_ to remove names for dropped sections.
- if (section == shstrtab_) return CreateSectionHeaderStringTable();
- // No other section currently needs adjustment.
- return section;
-}
-
-void Elf::PrepareDebugOutputInfo() {
- ClearOutputInfo();
-
- intptr_t file_offset = kElfHeaderSize;
-
- // This is the same for both the debugging and stripped output.
- program_table_file_offset_ = file_offset;
- program_table_entry_count_ = segments_.length() + kNumImplicitSegments;
- file_offset += ProgramTableSize();
-
- for (auto section : sections_) {
- // When splitting out debugging information, we only output the contents
- // of debug sections and the section header string table, so change the
- // section header information appropriately for other sections.
- auto const use_fake_info = section->output_type == Section::kMainOutput;
- section = AdjustForActiveSections(section);
- file_offset = PrepareDebugSection(section, file_offset, use_fake_info);
+ section->set_file_offset(file_offset);
+ file_offset += section->FileSize();
}
file_offset = Utils::RoundUp(file_offset, kElfSectionTableAlignment);
section_table_file_offset_ = file_offset;
- section_table_entry_count_ = active_sections_.length() + kNumInvalidSections;
- file_offset += SectionTableSize();
-
- VerifyOutputInfo();
+ section_table_file_size_ =
+ (sections_.length() + kNumInvalidSections) * kElfSectionTableEntrySize;
+ file_offset += section_table_file_size_;
}
-void Elf::PrepareMainOutputInfo() {
- ClearOutputInfo();
- intptr_t file_offset = kElfHeaderSize;
-
- program_table_file_offset_ = file_offset;
- program_table_entry_count_ = segments_.length() + kNumImplicitSegments;
- file_offset += ProgramTableSize();
-
- intptr_t skipped_sections = 0;
- for (auto section : sections_) {
- if (strip_ && section->output_type == Section::kDebugOutput) {
- skipped_sections += 1;
- continue;
- }
- section = AdjustForActiveSections(section);
- file_offset = PrepareMainSection(section, file_offset, skipped_sections);
- }
-
- file_offset = Utils::RoundUp(file_offset, kElfSectionTableAlignment);
- section_table_file_offset_ = file_offset;
- section_table_entry_count_ = active_sections_.length() + kNumInvalidSections;
- file_offset += SectionTableSize();
-
- VerifyOutputInfo();
-}
-
-void Elf::WriteHeader(StreamingWriteStream* stream) {
+void Elf::WriteHeader() {
#if defined(TARGET_ARCH_IS_32_BIT)
uint8_t size = elf::ELFCLASS32;
#else
@@ -821,26 +769,26 @@
0,
0,
0};
- WriteBytes(stream, e_ident, 16);
+ stream_->WriteBytes(e_ident, 16);
- WriteHalf(stream, elf::ET_DYN); // Shared library.
+ WriteHalf(elf::ET_DYN); // Shared library.
#if defined(TARGET_ARCH_IA32)
- WriteHalf(stream, elf::EM_386);
+ WriteHalf(elf::EM_386);
#elif defined(TARGET_ARCH_X64)
- WriteHalf(stream, elf::EM_X86_64);
+ WriteHalf(elf::EM_X86_64);
#elif defined(TARGET_ARCH_ARM)
- WriteHalf(stream, elf::EM_ARM);
+ WriteHalf(elf::EM_ARM);
#elif defined(TARGET_ARCH_ARM64)
- WriteHalf(stream, elf::EM_AARCH64);
+ WriteHalf(elf::EM_AARCH64);
#else
FATAL("Unknown ELF architecture");
#endif
- WriteWord(stream, elf::EV_CURRENT); // Version
- WriteAddr(stream, 0); // "Entry point"
- WriteOff(stream, program_table_file_offset_);
- WriteOff(stream, section_table_file_offset_);
+ WriteWord(elf::EV_CURRENT); // Version
+ WriteAddr(0); // "Entry point"
+ WriteOff(program_table_file_offset_);
+ WriteOff(section_table_file_offset_);
#if defined(TARGET_ARCH_ARM)
uword flags = elf::EF_ARM_ABI | (TargetCPUFeatures::hardfp_supported()
@@ -849,48 +797,31 @@
#else
uword flags = 0;
#endif
- WriteWord(stream, flags);
+ WriteWord(flags);
- WriteHalf(stream, kElfHeaderSize);
- WriteHalf(stream, kElfProgramTableEntrySize);
- WriteHalf(stream, program_table_entry_count_);
- WriteHalf(stream, kElfSectionTableEntrySize);
- WriteHalf(stream, section_table_entry_count_);
- // The section header string table is always last in the active sections.
- WriteHalf(stream, SectionTableIndex(active_sections_.Last()->section_index));
+ WriteHalf(kElfHeaderSize);
+ WriteHalf(kElfProgramTableEntrySize);
+ WriteHalf(segments_.length() + kNumImplicitSegments);
+ WriteHalf(kElfSectionTableEntrySize);
+ WriteHalf(sections_.length() + kNumInvalidSections);
+ WriteHalf(shstrtab_->section_index());
- ASSERT(stream->position() == kElfHeaderSize);
+ ASSERT(stream_->position() == kElfHeaderSize);
}
-void Elf::WriteProgramTable(StreamingWriteStream* stream) {
- ASSERT(stream->position() == program_table_file_offset_);
- auto const program_table_file_size = ProgramTableSize();
+void Elf::WriteProgramTable() {
+ ASSERT(stream_->position() == program_table_file_offset_);
// Self-reference to program header table. Required by Android but not by
// Linux. Must appear before any PT_LOAD entries.
{
+ ProgramTable program_table(program_table_file_offset_,
+ program_table_file_size_);
+
ASSERT(kNumImplicitSegments == 3);
- const intptr_t start = stream->position();
-#if defined(TARGET_ARCH_IS_32_BIT)
- WriteWord(stream, elf::PT_PHDR);
- WriteOff(stream, program_table_file_offset_); // File offset.
- WriteAddr(stream, program_table_file_offset_); // Virtual address.
- WriteAddr(stream, program_table_file_offset_); // Physical address, unused.
- WriteWord(stream, program_table_file_size);
- WriteWord(stream, program_table_file_size);
- WriteWord(stream, elf::PF_R);
- WriteWord(stream, kPageSize);
-#else
- WriteWord(stream, elf::PT_PHDR);
- WriteWord(stream, elf::PF_R);
- WriteOff(stream, program_table_file_offset_); // File offset.
- WriteAddr(stream, program_table_file_offset_); // Virtual address.
- WriteAddr(stream, program_table_file_offset_); // Physical address, unused.
- WriteXWord(stream, program_table_file_size);
- WriteXWord(stream, program_table_file_size);
- WriteXWord(stream, kPageSize);
-#endif
- const intptr_t end = stream->position();
+ const intptr_t start = stream_->position();
+ program_table.WriteSegmentEntry(this);
+ const intptr_t end = stream_->position();
ASSERT((end - start) == kElfProgramTableEntrySize);
}
// Load for self-reference to program header table. Required by Android but
@@ -901,71 +832,26 @@
// fixed num of segments based on the four pieces of a snapshot, but if we
// use more in the future we'll likely need to do something more compilated
// to generate DWARF without knowing a piece's virtual address in advance.
- RELEASE_ASSERT((program_table_file_offset_ + program_table_file_size) <
- kProgramTableSegmentSize);
+ auto const program_table_segment_size =
+ program_table_file_offset_ + program_table_file_size_;
+ RELEASE_ASSERT(program_table_segment_size < kProgramTableSegmentSize);
+
+ // We create a section that, when printed as a segment, contains the
+ // appropriate info for the program table.
+ ProgramTableLoad program_table_load(program_table_segment_size);
ASSERT(kNumImplicitSegments == 3);
- const intptr_t start = stream->position();
-
- // The Android dynamic linker in Jelly Bean incorrectly assumes that all
- // non-writable segments are continguous. We put BSS first, so we must make
- // this segment writable so it does not mark the BSS as read-only.
- //
- // The bug is here:
- // https://github.com/aosp-mirror/platform_bionic/blob/94963af28e445384e19775a838a29e6a71708179/linker/linker.c#L1991-L2001
-#if defined(TARGET_ARCH_IS_32_BIT)
- WriteWord(stream, elf::PT_LOAD);
- WriteOff(stream, 0); // File offset.
- WriteAddr(stream, 0); // Virtual address.
- WriteAddr(stream, 0); // Physical address, not used.
- WriteWord(stream, program_table_file_offset_ + program_table_file_size);
- WriteWord(stream, program_table_file_offset_ + program_table_file_size);
- WriteWord(stream, elf::PF_R | elf::PF_W);
- WriteWord(stream, kPageSize);
-#else
- WriteWord(stream, elf::PT_LOAD);
- WriteWord(stream, elf::PF_R | elf::PF_W);
- WriteOff(stream, 0); // File offset.
- WriteAddr(stream, 0); // Virtual address.
- WriteAddr(stream, 0); // Physical address, not used.
- WriteXWord(stream, program_table_file_offset_ + program_table_file_size);
- WriteXWord(stream, program_table_file_offset_ + program_table_file_size);
- WriteXWord(stream, kPageSize);
-#endif
- const intptr_t end = stream->position();
+ const intptr_t start = stream_->position();
+ program_table_load.WriteSegmentEntry(this);
+ const intptr_t end = stream_->position();
ASSERT((end - start) == kElfProgramTableEntrySize);
}
- // We need to write out the segment headers even in the debugging info,
- // even though there won't be any contents of those segments here and
- // so we should report sizes of 0.
- for (const auto section : segments_) {
- const intptr_t start = stream->position();
- // file_sizes_ corresponds to active_sections_, so we first need to
- // find the offset of this section in there.
- auto const active_sections_index =
- ActiveSectionsIndex(section->section_index);
- auto const file_size = file_sizes_.At(active_sections_index);
-#if defined(TARGET_ARCH_IS_32_BIT)
- WriteWord(stream, section->segment_type);
- WriteOff(stream, section->file_offset);
- WriteAddr(stream, section->memory_offset); // Virtual address.
- WriteAddr(stream, section->memory_offset); // Physical address, not used.
- WriteWord(stream, file_size);
- WriteWord(stream, section->memory_size);
- WriteWord(stream, section->segment_flags);
- WriteWord(stream, section->alignment);
-#else
- WriteWord(stream, section->segment_type);
- WriteWord(stream, section->segment_flags);
- WriteOff(stream, section->file_offset);
- WriteAddr(stream, section->memory_offset); // Virtual address.
- WriteAddr(stream, section->memory_offset); // Physical address, not used.
- WriteXWord(stream, file_size);
- WriteXWord(stream, section->memory_size);
- WriteXWord(stream, section->alignment);
-#endif
- const intptr_t end = stream->position();
+ for (intptr_t i = 0; i < segments_.length(); i++) {
+ Section* section = segments_[i];
+ const intptr_t start = stream_->position();
+ section->WriteSegmentEntry(this);
+ const intptr_t end = stream_->position();
ASSERT((end - start) == kElfProgramTableEntrySize);
}
@@ -973,111 +859,44 @@
// header table entries.
{
ASSERT(kNumImplicitSegments == 3);
- const intptr_t start = stream->position();
- auto const active_sections_index =
- ActiveSectionsIndex(dynamic_->section_index);
- auto const file_size = file_sizes_.At(active_sections_index);
-#if defined(TARGET_ARCH_IS_32_BIT)
- WriteWord(stream, elf::PT_DYNAMIC);
- WriteOff(stream, dynamic_->file_offset);
- WriteAddr(stream, dynamic_->memory_offset); // Virtual address.
- WriteAddr(stream, dynamic_->memory_offset); // Physical address, not used.
- WriteWord(stream, file_size);
- WriteWord(stream, dynamic_->memory_size);
- WriteWord(stream, dynamic_->segment_flags);
- WriteWord(stream, dynamic_->alignment);
-#else
- WriteWord(stream, elf::PT_DYNAMIC);
- WriteWord(stream, dynamic_->segment_flags);
- WriteOff(stream, dynamic_->file_offset);
- WriteAddr(stream, dynamic_->memory_offset); // Virtual address.
- WriteAddr(stream, dynamic_->memory_offset); // Physical address, not used.
- WriteXWord(stream, file_size);
- WriteXWord(stream, dynamic_->memory_size);
- WriteXWord(stream, dynamic_->alignment);
-#endif
- const intptr_t end = stream->position();
+ const intptr_t start = stream_->position();
+ dynamic_->WriteSegmentEntry(this, /*dynamic=*/true);
+ const intptr_t end = stream_->position();
ASSERT((end - start) == kElfProgramTableEntrySize);
}
}
-void Elf::WriteSectionTable(StreamingWriteStream* stream) {
- stream->Align(kElfSectionTableAlignment);
- ASSERT(stream->position() == section_table_file_offset_);
+void Elf::WriteSectionTable() {
+ stream_->Align(kElfSectionTableAlignment);
+
+ ASSERT(stream_->position() == section_table_file_offset_);
{
// The first entry in the section table is reserved and must be all zeros.
ASSERT(kNumInvalidSections == 1);
- const intptr_t start = stream->position();
-#if defined(TARGET_ARCH_IS_32_BIT)
- WriteWord(stream, 0);
- WriteWord(stream, 0);
- WriteWord(stream, 0);
- WriteAddr(stream, 0);
- WriteOff(stream, 0);
- WriteWord(stream, 0);
- WriteWord(stream, 0);
- WriteWord(stream, 0);
- WriteWord(stream, 0);
- WriteWord(stream, 0);
-#else
- WriteWord(stream, 0);
- WriteWord(stream, 0);
- WriteXWord(stream, 0);
- WriteAddr(stream, 0);
- WriteOff(stream, 0);
- WriteXWord(stream, 0);
- WriteWord(stream, 0);
- WriteWord(stream, 0);
- WriteXWord(stream, 0);
- WriteXWord(stream, 0);
-#endif
- const intptr_t end = stream->position();
+ const intptr_t start = stream_->position();
+ ReservedSection reserved;
+ reserved.WriteSectionEntry(this);
+ const intptr_t end = stream_->position();
ASSERT((end - start) == kElfSectionTableEntrySize);
}
- for (intptr_t i = 0; i < active_sections_.length(); i++) {
- Section* section = active_sections_[i];
- auto const name = section_names_.At(i);
- auto const type = section_types_.At(i);
- auto const file_size = file_sizes_.At(i);
- auto const link = SectionTableIndex(section->section_link);
-
- const intptr_t start = stream->position();
-#if defined(TARGET_ARCH_IS_32_BIT)
- WriteWord(stream, name);
- WriteWord(stream, type);
- WriteWord(stream, section->section_flags);
- WriteAddr(stream, section->memory_offset);
- WriteOff(stream, section->file_offset);
- WriteWord(stream, file_size); // Has different meaning for BSS.
- WriteWord(stream, link);
- WriteWord(stream, section->section_info);
- WriteWord(stream, section->alignment);
- WriteWord(stream, section->section_entry_size);
-#else
- WriteWord(stream, name);
- WriteWord(stream, type);
- WriteXWord(stream, section->section_flags);
- WriteAddr(stream, section->memory_offset);
- WriteOff(stream, section->file_offset);
- WriteXWord(stream, file_size); // Has different meaning for BSS.
- WriteWord(stream, link);
- WriteWord(stream, section->section_info);
- WriteXWord(stream, section->alignment);
- WriteXWord(stream, section->section_entry_size);
-#endif
- const intptr_t end = stream->position();
+ for (intptr_t i = 0; i < sections_.length(); i++) {
+ Section* section = sections_[i];
+ const intptr_t start = stream_->position();
+ section->WriteSectionEntry(this);
+ const intptr_t end = stream_->position();
ASSERT((end - start) == kElfSectionTableEntrySize);
}
}
-void Elf::WriteSections(StreamingWriteStream* stream) {
- for (auto section : output_sections_) {
- stream->Align(section->alignment);
- ASSERT(stream->position() == section->file_offset);
- section->Write(stream);
- ASSERT(stream->position() == section->file_offset + section->file_size);
+void Elf::WriteSections() {
+ for (intptr_t i = 0; i < sections_.length(); i++) {
+ Section* section = sections_[i];
+ stream_->Align(section->alignment);
+ ASSERT(stream_->position() == section->file_offset());
+ section->Write(this);
+ ASSERT(stream_->position() == section->file_offset() + section->FileSize());
}
}
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index f6ac23f..f270dac 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -9,7 +9,6 @@
#include "vm/compiler/runtime_api.h"
#include "vm/datastream.h"
#include "vm/growable_array.h"
-#include "vm/hash_map.h"
#include "vm/zone.h"
namespace dart {
@@ -22,14 +21,11 @@
class Elf : public ZoneAllocated {
public:
- Elf(Zone* zone,
- StreamingWriteStream* stream,
- bool strip,
- StreamingWriteStream* debug_stream = nullptr);
+ Elf(Zone* zone, StreamingWriteStream* stream);
static const intptr_t kPageSize = 4096;
- intptr_t NextMemoryOffset() const { return memory_offset_; }
+ intptr_t NextMemoryOffset() const;
intptr_t NextSectionIndex() const;
intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
@@ -41,108 +37,66 @@
void Finalize();
- static void WriteBytes(StreamingWriteStream* stream,
- const uint8_t* bytes,
- intptr_t size) {
- stream->WriteBytes(bytes, size);
+ intptr_t position() const { return stream_->position(); }
+ void WriteBytes(const uint8_t* b, intptr_t size) {
+ stream_->WriteBytes(b, size);
}
- static void WriteByte(StreamingWriteStream* stream, uint8_t value) {
- stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+ void WriteByte(uint8_t value) {
+ stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
- static void WriteHalf(StreamingWriteStream* stream, uint16_t value) {
- stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+ void WriteHalf(uint16_t value) {
+ stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
- static void WriteWord(StreamingWriteStream* stream, uint32_t value) {
- stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+ void WriteWord(uint32_t value) {
+ stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
- static void WriteAddr(StreamingWriteStream* stream,
- compiler::target::uword value) {
- stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+ void WriteAddr(compiler::target::uword value) {
+ stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
- static void WriteOff(StreamingWriteStream* stream,
- compiler::target::uword value) {
- stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+ void WriteOff(compiler::target::uword value) {
+ stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
#if defined(TARGET_ARCH_IS_64_BIT)
- static void WriteXWord(StreamingWriteStream* stream, uint64_t value) {
- stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+ void WriteXWord(uint64_t value) {
+ stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
#endif
private:
void AddSection(Section* section, const char* name);
- void AddSegment(Section* section);
+ intptr_t AddSectionSymbol(const Section* section,
+ const char* name,
+ intptr_t size);
- intptr_t ActiveSectionsIndex(intptr_t section_index) const;
- intptr_t SectionTableIndex(intptr_t section_index) const;
- intptr_t ProgramTableSize() const;
- intptr_t SectionTableSize() const;
-
- void ClearOutputInfo();
- // Checks that the output information used by the writing methods has been
- // properly constructed.
- void VerifyOutputInfo() const;
-
- // Creates a new version of shstrtab_ that only copies over names of active
- // sections. Sets the contents of section_names_ to indices in the new table.
- StringTable* CreateSectionHeaderStringTable();
- // Either returns the original section or a section like the old one that
- // also accounts for what sections are currently active.
- Section* AdjustForActiveSections(Section* section);
-
- // These methods return the new file offset taking into consideration the
- // alignment and size of the section.
- intptr_t PrepareDebugSection(Section* section,
- intptr_t start_offset,
- bool use_fake_info);
- intptr_t PrepareMainSection(Section* section,
- intptr_t start_offset,
- intptr_t skipped_sections);
-
- // These methods set up:
- // * Various information about file offsets
- // * The number of entries in the program and section tables
- // * An array of the active sections (i.e., those in the section table).
- // * An array of the sections that will be fully output.
- // * Some arrays of information used instead of the values of their
- // corresponding Section fields when creating the section table.
- void PrepareDebugOutputInfo();
- void PrepareMainOutputInfo();
-
- void WriteHeader(StreamingWriteStream* s);
- void WriteProgramTable(StreamingWriteStream* s);
- void WriteSectionTable(StreamingWriteStream* s);
- void WriteSections(StreamingWriteStream* s);
+ void ComputeFileOffsets();
+ void WriteHeader();
+ void WriteSectionTable();
+ void WriteProgramTable();
+ void WriteSections();
Zone* const zone_;
- const bool strip_;
StreamingWriteStream* const stream_;
- StreamingWriteStream* const debug_stream_;
- GrowableArray<Section*> sections_;
- GrowableArray<Section*> segments_;
- intptr_t memory_offset_ = 0;
- StringTable* shstrtab_ = nullptr;
- StringTable* dynstrtab_ = nullptr;
- SymbolTable* dynsym_ = nullptr;
- StringTable* strtab_ = nullptr;
- SymbolTable* symtab_ = nullptr;
+ // All our strings would fit in a single page. However, we use separate
+ // .shstrtab and .dynstr to work around a bug in Android's strip utility.
+ StringTable* const shstrtab_;
+ StringTable* const dynstrtab_;
+ SymbolTable* const dynsym_;
+
+ // Can only be created once the dynamic symbol table is complete.
DynamicTable* dynamic_ = nullptr;
- // Filled out during the Prepare*OutputInfo methods and used by the Write*
- // instance methods, as these values will differ between stripped and
- // debugging outputs.
- GrowableArray<Section*> active_sections_;
- GrowableArray<Section*> output_sections_;
- IntMap<intptr_t> adjusted_indices_;
- // These should all contain entries for the sections in active_sections_.
- GrowableArray<intptr_t> file_sizes_;
- GrowableArray<intptr_t> section_names_;
- GrowableArray<intptr_t> section_types_;
+ // The static tables are lazily created when static symbols are added.
+ StringTable* strtab_ = nullptr;
+ SymbolTable* symtab_ = nullptr;
+
+ GrowableArray<Section*> sections_;
+ GrowableArray<Section*> segments_;
+ intptr_t memory_offset_;
intptr_t section_table_file_offset_ = -1;
- intptr_t section_table_entry_count_ = -1;
+ intptr_t section_table_file_size_ = -1;
intptr_t program_table_file_offset_ = -1;
- intptr_t program_table_entry_count_ = -1;
+ intptr_t program_table_file_size_ = -1;
};
} // namespace dart
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 6c5a066..15700c1 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -221,12 +221,6 @@
: freelist_(),
heap_(heap),
pages_lock_(),
- pages_(NULL),
- pages_tail_(NULL),
- exec_pages_(NULL),
- exec_pages_tail_(NULL),
- large_pages_(NULL),
- image_pages_(NULL),
bump_top_(0),
bump_end_(0),
max_capacity_in_words_(max_capacity_in_words),
@@ -273,49 +267,95 @@
return page_size >> kWordSizeLog2;
}
+void PageSpace::AddPageLocked(HeapPage* page) {
+ if (pages_ == nullptr) {
+ pages_ = page;
+ } else {
+ pages_tail_->set_next(page);
+ }
+ pages_tail_ = page;
+}
+
+void PageSpace::AddLargePageLocked(HeapPage* page) {
+ if (large_pages_ == nullptr) {
+ large_pages_ = page;
+ } else {
+ large_pages_tail_->set_next(page);
+ }
+ large_pages_tail_ = page;
+}
+
+void PageSpace::AddExecPageLocked(HeapPage* page) {
+ if (exec_pages_ == nullptr) {
+ exec_pages_ = page;
+ } else {
+ if (FLAG_write_protect_code) {
+ exec_pages_tail_->WriteProtect(false);
+ }
+ exec_pages_tail_->set_next(page);
+ if (FLAG_write_protect_code) {
+ exec_pages_tail_->WriteProtect(true);
+ }
+ }
+ exec_pages_tail_ = page;
+}
+
+void PageSpace::RemovePageLocked(HeapPage* page, HeapPage* previous_page) {
+ if (previous_page != NULL) {
+ previous_page->set_next(page->next());
+ } else {
+ pages_ = page->next();
+ }
+ if (page == pages_tail_) {
+ pages_tail_ = previous_page;
+ }
+}
+
+void PageSpace::RemoveLargePageLocked(HeapPage* page, HeapPage* previous_page) {
+ if (previous_page != NULL) {
+ previous_page->set_next(page->next());
+ } else {
+ large_pages_ = page->next();
+ }
+ if (page == large_pages_tail_) {
+ large_pages_tail_ = previous_page;
+ }
+}
+
+void PageSpace::RemoveExecPageLocked(HeapPage* page, HeapPage* previous_page) {
+ if (previous_page != NULL) {
+ previous_page->set_next(page->next());
+ } else {
+ exec_pages_ = page->next();
+ }
+ if (page == exec_pages_tail_) {
+ exec_pages_tail_ = previous_page;
+ }
+}
+
HeapPage* PageSpace::AllocatePage(HeapPage::PageType type, bool link) {
{
MutexLocker ml(&pages_lock_);
if (!CanIncreaseCapacityInWordsLocked(kPageSizeInWords)) {
- return NULL;
+ return nullptr;
}
IncreaseCapacityInWordsLocked(kPageSizeInWords);
}
const bool is_exec = (type == HeapPage::kExecutable);
const char* name = Heap::RegionName(is_exec ? Heap::kCode : Heap::kOld);
HeapPage* page = HeapPage::Allocate(kPageSizeInWords, type, name);
- if (page == NULL) {
+ if (page == nullptr) {
RELEASE_ASSERT(!FLAG_abort_on_oom);
IncreaseCapacityInWords(-kPageSizeInWords);
- return NULL;
+ return nullptr;
}
MutexLocker ml(&pages_lock_);
if (link) {
- if (!is_exec) {
- if (pages_ == NULL) {
- pages_ = page;
- } else {
- pages_tail_->set_next(page);
- }
- pages_tail_ = page;
+ if (is_exec) {
+ AddExecPageLocked(page);
} else {
- // Should not allocate executable pages when running from a precompiled
- // snapshot.
- ASSERT(Dart::vm_snapshot_kind() != Snapshot::kFullAOT);
-
- if (exec_pages_ == NULL) {
- exec_pages_ = page;
- } else {
- if (FLAG_write_protect_code) {
- exec_pages_tail_->WriteProtect(false);
- }
- exec_pages_tail_->set_next(page);
- if (FLAG_write_protect_code) {
- exec_pages_tail_->WriteProtect(true);
- }
- }
- exec_pages_tail_ = page;
+ AddPageLocked(page);
}
}
@@ -332,26 +372,28 @@
{
MutexLocker ml(&pages_lock_);
if (!CanIncreaseCapacityInWordsLocked(page_size_in_words)) {
- return NULL;
+ return nullptr;
}
IncreaseCapacityInWordsLocked(page_size_in_words);
}
const bool is_exec = (type == HeapPage::kExecutable);
const char* name = Heap::RegionName(is_exec ? Heap::kCode : Heap::kOld);
HeapPage* page = HeapPage::Allocate(page_size_in_words, type, name);
- {
- MutexLocker ml(&pages_lock_);
- if (page == nullptr) {
- IncreaseCapacityInWordsLocked(-page_size_in_words);
- return nullptr;
- }
- page->set_next(large_pages_);
- large_pages_ = page;
- // Only one object in this page (at least until Array::MakeFixedLength
- // is called).
- page->set_object_end(page->object_start() + size);
+ MutexLocker ml(&pages_lock_);
+ if (page == nullptr) {
+ IncreaseCapacityInWordsLocked(-page_size_in_words);
+ return nullptr;
}
+ if (is_exec) {
+ AddExecPageLocked(page);
+ } else {
+ AddLargePageLocked(page);
+ }
+
+ // Only one object in this page (at least until Array::MakeFixedLength
+ // is called).
+ page->set_object_end(page->object_start() + size);
return page;
}
@@ -376,26 +418,10 @@
{
MutexLocker ml(&pages_lock_);
IncreaseCapacityInWordsLocked(-(page->memory_->size() >> kWordSizeLog2));
- if (!is_exec) {
- // Remove the page from the list of data pages.
- if (previous_page != NULL) {
- previous_page->set_next(page->next());
- } else {
- pages_ = page->next();
- }
- if (page == pages_tail_) {
- pages_tail_ = previous_page;
- }
+ if (is_exec) {
+ RemoveExecPageLocked(page, previous_page);
} else {
- // Remove the page from the list of executable pages.
- if (previous_page != NULL) {
- previous_page->set_next(page->next());
- } else {
- exec_pages_ = page->next();
- }
- if (page == exec_pages_tail_) {
- exec_pages_tail_ = previous_page;
- }
+ RemovePageLocked(page, previous_page);
}
}
// TODO(iposva): Consider adding to a pool of empty pages.
@@ -403,16 +429,10 @@
}
void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) {
- // Thread should be at a safepoint when this code is called and hence
- // it is not necessary to lock large_pages_.
- ASSERT(Thread::Current()->IsAtSafepoint());
- IncreaseCapacityInWords(-(page->memory_->size() >> kWordSizeLog2));
- // Remove the page from the list.
- if (previous_page != NULL) {
- previous_page->set_next(page->next());
- } else {
- large_pages_ = page->next();
- }
+ ASSERT(page->type() != HeapPage::kExecutable);
+ MutexLocker ml(&pages_lock_);
+ IncreaseCapacityInWordsLocked(-(page->memory_->size() >> kWordSizeLog2));
+ RemoveLargePageLocked(page, previous_page);
page->Deallocate();
}
@@ -1132,36 +1152,18 @@
OS::PrintErr(" done.\n");
}
- TIMELINE_FUNCTION_GC_DURATION(thread, "SweepLargeAndExecutablePages");
+ // Executable pages are always swept immediately to simplify
+ // code protection.
+
+ TIMELINE_FUNCTION_GC_DURATION(thread, "SweepExecutable");
GCSweeper sweeper;
-
- // During stop-the-world phases we should use bulk lock when adding
- // elements to the free list.
- MutexLocker mld(freelist_[HeapPage::kData].mutex());
- MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
-
- // Large and executable pages are always swept immediately.
HeapPage* prev_page = NULL;
- HeapPage* page = large_pages_;
- while (page != NULL) {
- HeapPage* next_page = page->next();
- const intptr_t words_to_end = sweeper.SweepLargePage(page);
- if (words_to_end == 0) {
- FreeLargePage(page, prev_page);
- } else {
- TruncateLargePage(page, words_to_end << kWordSizeLog2);
- prev_page = page;
- }
- // Advance to the next page.
- page = next_page;
- }
-
- prev_page = NULL;
- page = exec_pages_;
+ HeapPage* page = exec_pages_;
FreeList* freelist = &freelist_[HeapPage::kExecutable];
+ MutexLocker ml(freelist->mutex());
while (page != NULL) {
HeapPage* next_page = page->next();
- bool page_in_use = sweeper.SweepPage(page, freelist, true);
+ bool page_in_use = sweeper.SweepPage(page, freelist, true /*is_locked*/);
if (page_in_use) {
prev_page = page;
} else {
@@ -1175,12 +1177,14 @@
}
if (compact) {
+ SweepLarge();
Compact(thread);
set_phase(kDone);
} else if (FLAG_concurrent_sweep) {
ConcurrentSweep(isolate);
} else {
- BlockingSweep();
+ SweepLarge();
+ Sweep();
set_phase(kDone);
}
@@ -1213,19 +1217,38 @@
}
}
-void PageSpace::BlockingSweep() {
+void PageSpace::SweepLarge() {
+ TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "SweepLarge");
+
+ GCSweeper sweeper;
+ HeapPage* prev_page = nullptr;
+ HeapPage* page = large_pages_;
+ while (page != nullptr) {
+ HeapPage* next_page = page->next();
+ const intptr_t words_to_end = sweeper.SweepLargePage(page);
+ if (words_to_end == 0) {
+ FreeLargePage(page, prev_page);
+ } else {
+ TruncateLargePage(page, words_to_end << kWordSizeLog2);
+ prev_page = page;
+ }
+ // Advance to the next page.
+ page = next_page;
+ }
+}
+
+void PageSpace::Sweep() {
TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "Sweep");
- MutexLocker mld(freelist_[HeapPage::kData].mutex());
- MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
-
- // Sweep all regular sized pages now.
GCSweeper sweeper;
- HeapPage* prev_page = NULL;
+ HeapPage* prev_page = nullptr;
HeapPage* page = pages_;
- while (page != NULL) {
+ FreeList* freelist = &freelist_[HeapPage::kData];
+ MutexLocker ml(freelist_->mutex());
+ while (page != nullptr) {
HeapPage* next_page = page->next();
- bool page_in_use = sweeper.SweepPage(page, &freelist_[page->type()], true);
+ ASSERT(page->type() == HeapPage::kData);
+ bool page_in_use = sweeper.SweepPage(page, freelist, true /*is_locked*/);
if (page_in_use) {
prev_page = page;
} else {
@@ -1244,8 +1267,8 @@
void PageSpace::ConcurrentSweep(Isolate* isolate) {
// Start the concurrent sweeper task now.
- GCSweeper::SweepConcurrent(isolate, pages_, pages_tail_,
- &freelist_[HeapPage::kData]);
+ GCSweeper::SweepConcurrent(isolate, pages_, pages_tail_, large_pages_,
+ large_pages_tail_, &freelist_[HeapPage::kData]);
}
void PageSpace::Compact(Thread* thread) {
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 83ca216..417e14d 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -479,10 +479,19 @@
// Makes bump block walkable; do not call concurrently with mutator.
void MakeIterable() const;
+
+ void AddPageLocked(HeapPage* page);
+ void AddLargePageLocked(HeapPage* page);
+ void AddExecPageLocked(HeapPage* page);
+ void RemovePageLocked(HeapPage* page, HeapPage* previous_page);
+ void RemoveLargePageLocked(HeapPage* page, HeapPage* previous_page);
+ void RemoveExecPageLocked(HeapPage* page, HeapPage* previous_page);
+
HeapPage* AllocatePage(HeapPage::PageType type, bool link = true);
- void FreePage(HeapPage* page, HeapPage* previous_page);
HeapPage* AllocateLargePage(intptr_t size, HeapPage::PageType type);
+
void TruncateLargePage(HeapPage* page, intptr_t new_object_size_in_bytes);
+ void FreePage(HeapPage* page, HeapPage* previous_page);
void FreeLargePage(HeapPage* page, HeapPage* previous_page);
void FreePages(HeapPage* pages);
@@ -490,7 +499,8 @@
bool finalize,
int64_t pre_wait_for_sweepers,
int64_t pre_safe_point);
- void BlockingSweep();
+ void SweepLarge();
+ void Sweep();
void ConcurrentSweep(Isolate* isolate);
void Compact(Thread* thread);
@@ -513,12 +523,13 @@
// Use ExclusivePageIterator for safe access to these.
mutable Mutex pages_lock_;
- HeapPage* pages_;
- HeapPage* pages_tail_;
- HeapPage* exec_pages_;
- HeapPage* exec_pages_tail_;
- HeapPage* large_pages_;
- HeapPage* image_pages_;
+ HeapPage* pages_ = nullptr;
+ HeapPage* pages_tail_ = nullptr;
+ HeapPage* exec_pages_ = nullptr;
+ HeapPage* exec_pages_tail_ = nullptr;
+ HeapPage* large_pages_ = nullptr;
+ HeapPage* large_pages_tail_ = nullptr;
+ HeapPage* image_pages_ = nullptr;
// A block of memory in a data page, managed by bump allocation. The remainder
// is kept formatted as a FreeListElement, but is not in any freelist.
diff --git a/runtime/vm/heap/sweeper.cc b/runtime/vm/heap/sweeper.cc
index fa294d9..2786390 100644
--- a/runtime/vm/heap/sweeper.cc
+++ b/runtime/vm/heap/sweeper.cc
@@ -110,11 +110,15 @@
PageSpace* old_space,
HeapPage* first,
HeapPage* last,
+ HeapPage* large_first,
+ HeapPage* large_last,
FreeList* freelist)
: task_isolate_(isolate),
old_space_(old_space),
first_(first),
last_(last),
+ large_first_(large_first),
+ large_last_(large_last),
freelist_(freelist) {
ASSERT(task_isolate_ != NULL);
ASSERT(first_ != NULL);
@@ -132,14 +136,35 @@
ASSERT(result);
{
Thread* thread = Thread::Current();
+ ASSERT(thread->BypassSafepoints()); // Or we should be checking in.
TIMELINE_FUNCTION_GC_DURATION(thread, "ConcurrentSweep");
GCSweeper sweeper;
- HeapPage* page = first_;
+ HeapPage* page = large_first_;
HeapPage* prev_page = NULL;
-
while (page != NULL) {
- ASSERT(thread->BypassSafepoints()); // Or we should be checking in.
+ HeapPage* next_page;
+ if (page == large_last_) {
+ // Don't access page->next(), which would be a race with mutator
+ // allocating new pages.
+ next_page = NULL;
+ } else {
+ next_page = page->next();
+ }
+ ASSERT(page->type() == HeapPage::kData);
+ const intptr_t words_to_end = sweeper.SweepLargePage(page);
+ if (words_to_end == 0) {
+ old_space_->FreeLargePage(page, prev_page);
+ } else {
+ old_space_->TruncateLargePage(page, words_to_end << kWordSizeLog2);
+ prev_page = page;
+ }
+ page = next_page;
+ }
+
+ page = first_;
+ prev_page = NULL;
+ while (page != NULL) {
HeapPage* next_page;
if (page == last_) {
// Don't access page->next(), which would be a race with mutator
@@ -181,15 +206,20 @@
PageSpace* old_space_;
HeapPage* first_;
HeapPage* last_;
+ HeapPage* large_first_;
+ HeapPage* large_last_;
FreeList* freelist_;
};
void GCSweeper::SweepConcurrent(Isolate* isolate,
HeapPage* first,
HeapPage* last,
+ HeapPage* large_first,
+ HeapPage* large_last,
FreeList* freelist) {
bool result = Dart::thread_pool()->Run<ConcurrentSweeperTask>(
- isolate, isolate->heap()->old_space(), first, last, freelist);
+ isolate, isolate->heap()->old_space(), first, last, large_first,
+ large_last, freelist);
ASSERT(result);
}
diff --git a/runtime/vm/heap/sweeper.h b/runtime/vm/heap/sweeper.h
index 609b962..068a30d 100644
--- a/runtime/vm/heap/sweeper.h
+++ b/runtime/vm/heap/sweeper.h
@@ -38,6 +38,8 @@
static void SweepConcurrent(Isolate* isolate,
HeapPage* first,
HeapPage* last,
+ HeapPage* large_first,
+ HeapPage* large_last,
FreeList* freelist);
};
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index ee269b4..f3bae71 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -447,20 +447,28 @@
Elf* debug_elf)
: ImageWriter(thread->heap()),
assembly_stream_(512 * KB, callback, callback_data),
- dwarf_(nullptr) {
+ assembly_dwarf_(nullptr),
+ debug_dwarf_(nullptr) {
#if defined(DART_PRECOMPILER)
Zone* zone = Thread::Current()->zone();
- if (!strip || debug_elf != nullptr) {
- dwarf_ =
- new (zone) Dwarf(zone, strip ? nullptr : &assembly_stream_, debug_elf);
+ if (!strip) {
+ assembly_dwarf_ =
+ new (zone) Dwarf(zone, &assembly_stream_, /*elf=*/nullptr);
+ }
+ if (debug_elf != nullptr) {
+ debug_dwarf_ =
+ new (zone) Dwarf(zone, /*assembly_stream=*/nullptr, debug_elf);
}
#endif
}
void AssemblyImageWriter::Finalize() {
#ifdef DART_PRECOMPILER
- if (dwarf_ != nullptr) {
- dwarf_->Write();
+ if (assembly_dwarf_ != nullptr) {
+ assembly_dwarf_->Write();
+ }
+ if (debug_dwarf_ != nullptr) {
+ debug_dwarf_->Write();
}
#endif
}
@@ -551,9 +559,9 @@
#if defined(DART_PRECOMPILER)
const char* bss_symbol =
vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss";
- intptr_t segment_base = 0;
- if ((dwarf_ != nullptr) && (dwarf_->elf() != nullptr)) {
- segment_base = dwarf_->elf()->NextMemoryOffset();
+ intptr_t debug_segment_base = 0;
+ if (debug_dwarf_ != nullptr) {
+ debug_segment_base = debug_dwarf_->elf()->NextMemoryOffset();
}
#endif
@@ -670,12 +678,13 @@
intptr_t dwarf_index = i;
#ifdef DART_PRECOMPILER
// Create a label for use by DWARF.
- if (dwarf_ != nullptr) {
- intptr_t virtual_address = -1;
- if (auto const elf = dwarf_->elf()) {
- virtual_address = segment_base + Image::kHeaderSize + text_offset;
- }
- dwarf_index = dwarf_->AddCode(code, virtual_address);
+ if (assembly_dwarf_ != nullptr) {
+ dwarf_index = assembly_dwarf_->AddCode(code);
+ }
+ if (debug_dwarf_ != nullptr) {
+ auto const virtual_address =
+ debug_segment_base + Image::kHeaderSize + text_offset;
+ debug_dwarf_->AddCode(code, virtual_address);
}
#endif
// 2. Write a label at the entry point.
@@ -737,7 +746,7 @@
FrameUnwindEpilogue();
#if defined(DART_PRECOMPILER)
- if ((dwarf_ != nullptr) && (dwarf_->elf() != nullptr)) {
+ if (debug_dwarf_ != nullptr) {
// We need to generate a text segment of the appropriate size in the ELF
// for two reasons:
//
@@ -752,8 +761,10 @@
//
// Since we won't actually be adding the instructions to the ELF output,
// we can pass nullptr for the bytes of the section/segment.
- dwarf_->elf()->AddText(instructions_symbol, /*bytes=*/nullptr,
- Image::kHeaderSize + text_offset);
+ auto const debug_segment_base2 =
+ debug_dwarf_->elf()->AddText(instructions_symbol, /*bytes=*/nullptr,
+ Image::kHeaderSize + text_offset);
+ ASSERT(debug_segment_base2 == debug_segment_base);
}
assembly_stream_.Print(".bss\n");
@@ -874,19 +885,22 @@
uint8_t** instructions_blob_buffer,
ReAlloc alloc,
intptr_t initial_size,
+ Dwarf* debug_dwarf,
intptr_t bss_base,
Elf* elf,
- Dwarf* dwarf)
+ Dwarf* elf_dwarf)
: ImageWriter(thread->heap()),
instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size),
elf_(elf),
- dwarf_(dwarf),
- bss_base_(bss_base) {
+ elf_dwarf_(elf_dwarf),
+ bss_base_(bss_base),
+ debug_dwarf_(debug_dwarf) {
#if defined(DART_PRECOMPILER)
- RELEASE_ASSERT(bss_base_ == 0 || elf_ != nullptr);
+ RELEASE_ASSERT(elf_ == nullptr || elf_dwarf_ == nullptr ||
+ elf_dwarf_->elf() == elf_);
#else
RELEASE_ASSERT(elf_ == nullptr);
- RELEASE_ASSERT(dwarf_ == nullptr);
+ RELEASE_ASSERT(elf_dwarf_ == nullptr);
#endif
}
@@ -904,6 +918,10 @@
if (elf_ != nullptr) {
segment_base = elf_->NextMemoryOffset();
}
+ intptr_t debug_segment_base = 0;
+ if (debug_dwarf_ != nullptr) {
+ debug_segment_base = debug_dwarf_->elf()->NextMemoryOffset();
+ }
#endif
// This header provides the gap to make the instructions snapshot look like a
@@ -911,7 +929,7 @@
instructions_blob_stream_.WriteTargetWord(instructions_length);
#if defined(DART_PRECOMPILER)
instructions_blob_stream_.WriteTargetWord(
- bss_base_ != 0 ? bss_base_ - segment_base : 0);
+ elf_ != nullptr ? bss_base_ - segment_base : 0);
#else
instructions_blob_stream_.WriteTargetWord(0); // No relocations.
#endif
@@ -1000,19 +1018,24 @@
#endif
#if defined(DART_PRECOMPILER)
- if (elf_ != nullptr && dwarf_ != nullptr) {
+ if (elf_ != nullptr && elf_dwarf_ != nullptr) {
+ const auto& code = *instructions_[i].code_;
auto const virtual_address = segment_base + payload_stream_start;
- const Code& code = *instructions_[i].code_;
- dwarf_->AddCode(code, virtual_address);
+ elf_dwarf_->AddCode(code, virtual_address);
elf_->AddStaticSymbol(elf_->NextSectionIndex(),
namer.AssemblyNameFor(i, code), virtual_address);
}
+ if (debug_dwarf_ != nullptr) {
+ const auto& code = *instructions_[i].code_;
+ auto const virtual_address = debug_segment_base + payload_stream_start;
+ debug_dwarf_->AddCode(code, virtual_address);
+ }
// Don't patch the relocation if we're not generating ELF. The regular blobs
// format does not yet support these relocations. Use
// Code::VerifyBSSRelocations to check whether the relocations are patched
// or not after loading.
- if (bss_base_ != 0) {
+ if (elf_ != nullptr) {
const intptr_t current_stream_position =
instructions_blob_stream_.Position();
@@ -1056,14 +1079,20 @@
ASSERT(instructions_blob_stream_.bytes_written() == instructions_length);
#ifdef DART_PRECOMPILER
+ const char* instructions_symbol =
+ vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions";
if (elf_ != nullptr) {
- const char* instructions_symbol = vm ? "_kDartVmSnapshotInstructions"
- : "_kDartIsolateSnapshotInstructions";
- intptr_t segment_base2 =
+ auto const segment_base2 =
elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
instructions_blob_stream_.bytes_written());
ASSERT(segment_base == segment_base2);
}
+ if (debug_dwarf_ != nullptr) {
+ auto const debug_segment_base2 = debug_dwarf_->elf()->AddText(
+ instructions_symbol, instructions_blob_stream_.buffer(),
+ instructions_blob_stream_.bytes_written());
+ ASSERT(debug_segment_base == debug_segment_base2);
+ }
#endif
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 4b1aa9a..691f22c 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -346,7 +346,8 @@
}
StreamingWriteStream assembly_stream_;
- Dwarf* dwarf_;
+ Dwarf* assembly_dwarf_;
+ Dwarf* debug_dwarf_;
DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
};
@@ -357,9 +358,10 @@
uint8_t** instructions_blob_buffer,
ReAlloc alloc,
intptr_t initial_size,
+ Dwarf* debug_dwarf = nullptr,
intptr_t bss_base = 0,
Elf* elf = nullptr,
- Dwarf* dwarf = nullptr);
+ Dwarf* elf_dwarf = nullptr);
virtual void WriteText(WriteStream* clustered_stream, bool vm);
@@ -372,8 +374,9 @@
WriteStream instructions_blob_stream_;
Elf* const elf_;
- Dwarf* const dwarf_;
+ Dwarf* const elf_dwarf_;
const intptr_t bss_base_;
+ Dwarf* const debug_dwarf_;
DISALLOW_COPY_AND_ASSIGN(BlobImageWriter);
};
diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc
index cb89d2c..c971495 100644
--- a/runtime/vm/kernel.cc
+++ b/runtime/vm/kernel.cc
@@ -750,13 +750,14 @@
const auto& type_params =
TypeArguments::Handle(zone, function.type_parameters());
+ const NNBDMode nnbd_mode = function.nnbd_mode();
if (!type_params.IsNull()) {
auto& type_param = TypeParameter::Handle(zone);
auto& bound = AbstractType::Handle(zone);
for (intptr_t i = 0, n = type_params.Length(); i < n; ++i) {
type_param ^= type_params.TypeAt(i);
bound = type_param.bound();
- if (!bound.IsTopType() && !type_param.IsGenericCovariantImpl()) {
+ if (!bound.IsTopType(nnbd_mode) && !type_param.IsGenericCovariantImpl()) {
return true;
}
}
@@ -770,7 +771,7 @@
auto& type = AbstractType::Handle(zone);
for (intptr_t i = function.NumImplicitParameters(); i < num_params; ++i) {
type = function.ParameterTypeAt(i);
- if (!type.IsTopType() && !is_generic_covariant_impl.Contains(i) &&
+ if (!type.IsTopType(nnbd_mode) && !is_generic_covariant_impl.Contains(i) &&
!is_covariant.Contains(i)) {
return true;
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 48565d2..8564b07 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -4547,7 +4547,7 @@
}
const AbstractType& other_type_arg =
AbstractType::Handle(zone, other_type_arguments.TypeAt(0));
- if (other_type_arg.IsTopType()) {
+ if (other_type_arg.IsTopType(mode)) {
return true;
}
if (!type_arguments.IsNull() && this_class.IsFutureClass()) {
@@ -5366,7 +5366,7 @@
AbstractType& type = AbstractType::Handle();
for (intptr_t i = 0; i < len; i++) {
type = TypeAt(from_index + i);
- if (type.IsNull() || !type.IsTopType()) {
+ if (type.IsNull() || !type.IsTopType(mode)) {
return false;
}
}
@@ -7379,7 +7379,7 @@
Heap::Space space) const {
const AbstractType& param_type =
AbstractType::Handle(ParameterTypeAt(parameter_position));
- if (param_type.IsTopType()) {
+ if (param_type.IsTopType(mode)) {
return true;
}
const AbstractType& other_param_type =
@@ -7457,7 +7457,7 @@
const AbstractType& other_res_type =
AbstractType::Handle(zone, other.result_type());
// 'void Function()' is a subtype of 'Object Function()'.
- if (!other_res_type.IsTopType()) {
+ if (!other_res_type.IsTopType(mode)) {
const AbstractType& res_type = AbstractType::Handle(zone, result_type());
if (!res_type.IsSubtypeOf(mode, other_res_type, space)) {
return false;
@@ -16886,37 +16886,25 @@
ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time.
// Note that Object::sentinel() has Null class, but !IsNull().
ASSERT(raw() != Object::sentinel().raw());
- if (FLAG_strong_non_nullable_type_checks) {
- if (IsNull()) {
- // In a legacy library, compute
- // NNBD_SUBTYPE(other, Null) || NNBD_SUBTYPE(Object, other)
- // In an opted-in library, compute
- // NNBD_SUBTYPE(Null, other).
- return Instance::NullIsInstanceOf(mode, other,
- other_instantiator_type_arguments,
- other_function_type_arguments);
- }
- // Compute NNBD_SUBTYPE(runtimeType, other).
- return RuntimeTypeIsSubtypeOf(mode, other,
- other_instantiator_type_arguments,
- other_function_type_arguments);
- }
if (IsNull()) {
if (mode == NNBDMode::kOptedInLib) {
- // Compute NNBD_SUBTYPE(Null, other).
+ // Compute NNBD_SUBTYPE(Null, other), either in weak or strong mode.
return Instance::NNBD_NullIsInstanceOf(other,
other_instantiator_type_arguments,
other_function_type_arguments);
}
ASSERT(mode == NNBDMode::kLegacyLib);
- // Compute the same subtyping result as pre-nnbd Dart:
- // LEGACY_SUBTYPE(other, Null) || LEGACY_SUBTYPE(Object, other).
- return Instance::NullIsInstanceOf(NNBDMode::kLegacyLib, other,
- other_instantiator_type_arguments,
- other_function_type_arguments);
+ // In weak mode,
+ // compute LEGACY_SUBTYPE(other, Null) || LEGACY_SUBTYPE(Object, other).
+ // In strong mode,
+ // compute NNBD_SUBTYPE(other, Null) || NNBD_SUBTYPE(Object, other).
+ // Note that both expressions yield the same results for any 'other' type.
+ return Instance::Legacy_NullIsInstanceOf(other,
+ other_instantiator_type_arguments,
+ other_function_type_arguments);
}
- // Compute the same subtyping result as pre-nnbd Dart:
- // LEGACY_SUBTYPE(runtimeType, other).
+ // In strong mode, compute NNBD_SUBTYPE(runtimeType, other).
+ // In weak mode, compute LEGACY_SUBTYPE(runtimeType, other).
return RuntimeTypeIsSubtypeOf(mode, other, other_instantiator_type_arguments,
other_function_type_arguments);
}
@@ -16943,47 +16931,38 @@
// In strong mode, for kLegacyLib mode:
// return NNBD_SUBTYPE(other, Null) || NNBD_SUBTYPE(Object, other).
-// In strong mode, for kOptedInLib mode:
-// return NNBD_SUBTYPE(Null, other).
// In weak mode, for kLegacyLib mode:
// return LEGACY_SUBTYPE(other, Null) || LEGACY_SUBTYPE(Object, other).
-// The NNBDMode::kOptedInLib mode is never passed in weak mode.
-bool Instance::NullIsInstanceOf(
- NNBDMode mode,
+// Note that both expressions yield the same results.
+// Ignore value of strong flag value.
+bool Instance::Legacy_NullIsInstanceOf(
const AbstractType& other,
const TypeArguments& other_instantiator_type_arguments,
const TypeArguments& other_function_type_arguments) {
- ASSERT(FLAG_strong_non_nullable_type_checks || mode != NNBDMode::kOptedInLib);
- if (other.IsNullType() || other.IsTopType()) {
+ if (other.IsNullType() || other.Legacy_IsTopType()) {
return true;
}
AbstractType& instantiated_other = AbstractType::Handle(other.raw());
if (!other.IsInstantiated()) {
instantiated_other = other.InstantiateFrom(
- mode, other_instantiator_type_arguments, other_function_type_arguments,
- kAllFree, NULL, Heap::kOld);
+ NNBDMode::kLegacyLib, other_instantiator_type_arguments,
+ other_function_type_arguments, kAllFree, NULL, Heap::kOld);
if (instantiated_other.IsTypeRef()) {
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
- if (instantiated_other.IsNullType() || instantiated_other.IsTopType()) {
- return true;
- }
}
// instantiated_other is not modified if not FutureOr<T>.
while (instantiated_other.IsFutureOr(&instantiated_other)) {
}
- if (instantiated_other.IsNullType() || instantiated_other.IsTopType()) {
- return true;
- }
- if (FLAG_strong_non_nullable_type_checks) {
- const Nullability other_nullability = instantiated_other.nullability();
- return other_nullability == Nullability::kNullable ||
- other_nullability == Nullability::kLegacy;
- }
- return false;
+ return instantiated_other.IsNullType() ||
+ instantiated_other.Legacy_IsTopType();
}
-// Return NNBD_SUBTYPE(Null, other) independently of strong flag value.
+// In strong mode, for kOptedInLib mode:
+// return NNBD_SUBTYPE(Null, other).
+// In weak mode, for kOptedInLib mode:
+// return NNBD_SUBTYPE(Null, other).
+// Ignore value of strong flag value.
bool Instance::NNBD_NullIsInstanceOf(
const AbstractType& other,
const TypeArguments& other_instantiator_type_arguments,
@@ -17024,7 +17003,7 @@
ASSERT(!other.IsDynamicType());
ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time.
// Instance may not have runtimeType dynamic, void, or Never.
- if (other.IsTopType()) {
+ if (other.IsTopType(mode)) {
return true;
}
// In weak testing mode, Null type is a subtype of any type.
@@ -17046,7 +17025,7 @@
if (instantiated_other.IsTypeRef()) {
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
- if (instantiated_other.IsTopType() ||
+ if (instantiated_other.IsTopType(mode) ||
instantiated_other.IsDartFunctionType()) {
return true;
}
@@ -17086,7 +17065,7 @@
if (instantiated_other.IsTypeRef()) {
instantiated_other = TypeRef::Cast(instantiated_other).type();
}
- if (instantiated_other.IsTopType()) {
+ if (instantiated_other.IsTopType(mode)) {
return true;
}
}
@@ -17123,7 +17102,7 @@
TypeArguments::Handle(zone, other.arguments());
const AbstractType& other_type_arg =
AbstractType::Handle(zone, other_type_arguments.TypeAt(0));
- if (other_type_arg.IsTopType()) {
+ if (other_type_arg.IsTopType(mode)) {
return true;
}
if (Class::Handle(zone, clazz()).IsFutureClass()) {
@@ -17724,32 +17703,24 @@
!IsNullable();
}
-bool AbstractType::IsTopType() const {
+bool AbstractType::IsTopType(NNBDMode mode) const {
+ return (FLAG_strong_non_nullable_type_checks || mode == NNBDMode::kOptedInLib)
+ ? NNBD_IsTopType()
+ : Legacy_IsTopType();
+}
+
+bool AbstractType::Legacy_IsTopType() const {
const classid_t cid = type_class_id();
if (cid == kIllegalCid) { // Includes TypeParameter.
return false;
}
- if (cid == kDynamicCid || cid == kVoidCid) {
+ if (cid == kDynamicCid || cid == kVoidCid || cid == kInstanceCid) {
return true;
}
- if (cid == kInstanceCid) { // Object type.
- return !FLAG_strong_non_nullable_type_checks ||
- !IsNonNullable(); // kLegacy or kNullable.
- }
// FutureOr<T> where T is a top type behaves as a top type.
- Thread* thread = Thread::Current();
- Zone* zone = thread->zone();
- if (Class::Handle(zone, type_class()).IsFutureOrClass()) {
- if (arguments() == TypeArguments::null()) {
- return true;
- }
- const TypeArguments& type_arguments =
- TypeArguments::Handle(zone, arguments());
- const AbstractType& type_arg =
- AbstractType::Handle(zone, type_arguments.TypeAt(0));
- if (type_arg.IsTopType()) {
- return true;
- }
+ AbstractType& type_arg = AbstractType::Handle(raw());
+ if (IsFutureOr(&type_arg)) {
+ return type_arg.Legacy_IsTopType();
}
return false;
}
@@ -17765,21 +17736,10 @@
if (cid == kInstanceCid) { // Object type.
return !IsNonNullable(); // kLegacy or kNullable.
}
-
// FutureOr<T> where T is a top type behaves as a top type.
- Thread* thread = Thread::Current();
- Zone* zone = thread->zone();
- if (Class::Handle(zone, type_class()).IsFutureOrClass()) {
- if (arguments() == TypeArguments::null()) {
- return true;
- }
- const TypeArguments& type_arguments =
- TypeArguments::Handle(zone, arguments());
- const AbstractType& type_arg =
- AbstractType::Handle(zone, type_arguments.TypeAt(0));
- if (type_arg.NNBD_IsTopType()) {
- return true;
- }
+ AbstractType& type_arg = AbstractType::Handle(raw());
+ if (IsFutureOr(&type_arg)) {
+ return type_arg.NNBD_IsTopType();
}
return false;
}
@@ -17839,6 +17799,9 @@
Class& cls = thread->ClassHandle();
cls = type_class();
if (cls.IsFutureOrClass()) {
+ if (type_arg == nullptr) {
+ return true;
+ }
if (arguments() == TypeArguments::null()) {
*type_arg = Type::dynamic_type().raw();
return true;
@@ -17858,7 +17821,7 @@
Heap::Space space) const {
ASSERT(IsFinalized());
ASSERT(other.IsFinalized());
- if (other.IsTopType() || IsNeverType()) {
+ if (other.IsTopType(mode) || IsNeverType()) {
return true;
}
if (IsDynamicType() || IsVoidType()) {
@@ -17995,7 +17958,7 @@
TypeArguments::Handle(zone, other.arguments());
const AbstractType& other_type_arg =
AbstractType::Handle(zone, other_type_arguments.TypeAt(0));
- if (other_type_arg.IsTopType()) {
+ if (other_type_arg.IsTopType(mode)) {
return true;
}
// Retry the IsSubtypeOf check after unwrapping type arg of FutureOr.
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 400eeaa..c36d28c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -6639,15 +6639,17 @@
const TypeArguments& other_instantiator_type_arguments,
const TypeArguments& other_function_type_arguments) const;
- // Return true if the null instance is an instance of other type.
- static bool NullIsInstanceOf(
- NNBDMode mode,
+ // Return true if the null instance is an instance of other type according to
+ // legacy semantics (independently of the current value of the strong flag).
+ // It only makes sense in a legacy library.
+ static bool Legacy_NullIsInstanceOf(
const AbstractType& other,
const TypeArguments& other_instantiator_type_arguments,
const TypeArguments& other_function_type_arguments);
// Return true if the null instance is an instance of other type according to
// NNBD semantics (independently of the current value of the strong flag).
+ // It only makes sense in an opted-in library.
static bool NNBD_NullIsInstanceOf(
const AbstractType& other,
const TypeArguments& other_instantiator_type_arguments,
@@ -7123,10 +7125,16 @@
bool IsObjectType() const { return type_class_id() == kInstanceCid; }
// Check if this type represents a top type.
- bool IsTopType() const;
+ bool IsTopType(NNBDMode mode) const;
+
+ // Check if this type represents a top type according to legacy
+ // semantics (independently of the current value of the strong flag or of the
+ // nnbd mode).
+ bool Legacy_IsTopType() const;
// Check if this type represents a top type according to NNBD
- // semantics (independently of the current value of the strong flag).
+ // semantics (independently of the current value of the strong flag or of the
+ // nnbd mode).
bool NNBD_IsTopType() const;
// Check if this type represents the 'bool' type.
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 94e8ef0..4b38e2d 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -678,20 +678,24 @@
}
}
-CountingPage* HeapSnapshotWriter::FindCountingPage(RawObject* obj) const {
- if (obj->IsOldObject()) {
- const uword addr = RawObject::ToAddr(obj);
- for (intptr_t i = 0; i < kMaxImagePages; i++) {
- if ((addr - image_page_ranges_[i].base) < image_page_ranges_[i].size) {
- return nullptr; // On an image page.
- }
+bool HeapSnapshotWriter::OnImagePage(RawObject* obj) const {
+ const uword addr = RawObject::ToAddr(obj);
+ for (intptr_t i = 0; i < kMaxImagePages; i++) {
+ if ((addr - image_page_ranges_[i].base) < image_page_ranges_[i].size) {
+ return true;
}
+ }
+ return false;
+}
+
+CountingPage* HeapSnapshotWriter::FindCountingPage(RawObject* obj) const {
+ if (obj->IsOldObject() && !OnImagePage(obj)) {
// On a regular or large page.
HeapPage* page = HeapPage::Of(obj);
return reinterpret_cast<CountingPage*>(page->forwarding_page());
}
- // In new space.
+ // On an image page or in new space.
return nullptr;
}
@@ -713,14 +717,22 @@
return 0;
}
+ if (FLAG_write_protect_code && obj->IsInstructions() && !OnImagePage(obj)) {
+ // A non-writable alias mapping may exist for instruction pages.
+ obj = HeapPage::ToWritable(obj);
+ }
+
CountingPage* counting_page = FindCountingPage(obj);
+ intptr_t id;
if (counting_page != nullptr) {
// Likely: object on an ordinary page.
- return counting_page->Lookup(RawObject::ToAddr(obj));
+ id = counting_page->Lookup(RawObject::ToAddr(obj));
} else {
// Unlikely: new space object, or object on a large or image page.
- return thread()->heap()->GetObjectId(obj);
+ id = thread()->heap()->GetObjectId(obj);
}
+ ASSERT(id != 0);
+ return id;
}
void HeapSnapshotWriter::ClearObjectIds() {
diff --git a/runtime/vm/object_graph.h b/runtime/vm/object_graph.h
index 2f2f80a..f05af3d 100644
--- a/runtime/vm/object_graph.h
+++ b/runtime/vm/object_graph.h
@@ -190,6 +190,7 @@
static const intptr_t kPreferredChunkSize = MB;
void SetupCountingPages();
+ bool OnImagePage(RawObject* obj) const;
CountingPage* FindCountingPage(RawObject* obj) const;
void EnsureAvailable(intptr_t needed);
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index 055a382..05985ab 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -8,6 +8,9 @@
#include "vm/os.h"
#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+
#include <fuchsia/deprecatedtimezone/cpp/fidl.h>
#include <lib/sys/cpp/service_directory.h>
#include <zircon/process.h>
@@ -20,6 +23,27 @@
namespace dart {
+// The data directory containing ICU timezone data files.
+static constexpr char kICUTZDataDir[] = "/config/data/tzdata/icu/44/le";
+
+// Initializes the source of timezone data if available. Timezone data file in
+// Fuchsia is at a fixed directory path. Returns true on success.
+bool InitializeTZData() {
+ // Try opening the path to check if present. No need to verify that it is a
+ // directory since ICU loading will return an error if the TZ data path is
+ // wrong.
+ int fd = openat(AT_FDCWD, kICUTZDataDir, O_RDONLY);
+ if (fd < 0) {
+ return false;
+ }
+ // 0 == Not overwriting the env var if already set.
+ setenv("ICU_TIMEZONE_FILES_DIR", kICUTZDataDir, 0);
+ if (!close(fd)) {
+ return false;
+ }
+ return true;
+}
+
#ifndef PRODUCT
DEFINE_FLAG(bool,
@@ -239,6 +263,7 @@
}
void OS::Init() {
+ InitializeTZData();
auto services = sys::ServiceDirectory::CreateFromNamespace();
services->Connect(tz.NewRequest());
}
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index bc3a571..76e30bd 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1244,7 +1244,7 @@
// call originated in a legacy library. Note that the type test against a
// non-legacy type (even in a legacy library) such as dynamic, void, or Null
// yield the same result independently of the mode used.
- NNBDMode mode =
+ const NNBDMode mode =
type.IsLegacy() ? NNBDMode::kLegacyLib : NNBDMode::kOptedInLib;
const bool result = receiver.IsInstanceOf(
mode, type, Object::null_type_arguments(), Object::null_type_arguments());
@@ -2409,8 +2409,9 @@
if (FLAG_shared_slow_path_triggers_gc) {
isolate->heap()->CollectAllGarbage();
}
- const auto& integer_box =
- Integer::Handle(zone, Integer::NewFromUint64(0x00ff00ff00ff0000));
+ constexpr uint64_t val = 0x7fffffff7fffffff;
+ ASSERT(!Smi::IsValid(static_cast<int64_t>(val)));
+ const auto& integer_box = Integer::Handle(zone, Integer::NewFromUint64(val));
arguments.SetReturn(integer_box);
};
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index 2200cb1..6c3a3fa 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -100,20 +100,16 @@
// `null` and patch these later in `Object::FinishInit()`.
if (!StubCode::HasBeenInitialized()) {
ASSERT(type.IsType());
- ASSERT(cid == kDynamicCid || cid == kVoidCid | cid == kNeverCid);
+ ASSERT(cid == kDynamicCid || cid == kVoidCid || cid == kNeverCid);
return Code::null();
}
- // TODO(regis): Revisit when type checking mode is not kLegacy anymore.
- if (cid == kDynamicCid || cid == kVoidCid || cid == kInstanceCid) {
+ if (cid == kDynamicCid || cid == kVoidCid ||
+ (cid == kInstanceCid &&
+ (!FLAG_strong_non_nullable_type_checks || !type.IsNonNullable()))) {
return StubCode::TopTypeTypeTest().raw();
}
- if (cid == kNeverCid) {
- // TODO(regis): Revisit.
- return StubCode::StubCode::DefaultTypeTest().raw();
- }
-
if (type.IsType() || type.IsTypeParameter()) {
const bool should_specialize = !FLAG_precompiled_mode && lazy_specialize;
return should_specialize ? StubCode::LazySpecializeTypeTest().raw()
diff --git a/sdk/lib/_http/http_date.dart b/sdk/lib/_http/http_date.dart
index edeb98f..ab24b87 100644
--- a/sdk/lib/_http/http_date.dart
+++ b/sdk/lib/_http/http_date.dart
@@ -116,38 +116,6 @@
"Nov",
"Dec"
];
- const List wkdaysLowerCase = const [
- "mon",
- "tue",
- "wed",
- "thu",
- "fri",
- "sat",
- "sun"
- ];
- const List weekdaysLowerCase = const [
- "monday",
- "tuesday",
- "wednesday",
- "thursday",
- "friday",
- "saturday",
- "sunday"
- ];
- const List monthsLowerCase = const [
- "jan",
- "feb",
- "mar",
- "apr",
- "may",
- "jun",
- "jul",
- "aug",
- "sep",
- "oct",
- "nov",
- "dec"
- ];
final int formatRfc1123 = 0;
final int formatRfc850 = 1;
@@ -221,7 +189,7 @@
try {
int value = int.parse(tmp);
return value;
- } on FormatException catch (e) {
+ } on FormatException {
throw new HttpException("Invalid HTTP date $date");
}
}
diff --git a/sdk/lib/_http/http_headers.dart b/sdk/lib/_http/http_headers.dart
index 028fd2d..30532d5 100644
--- a/sdk/lib/_http/http_headers.dart
+++ b/sdk/lib/_http/http_headers.dart
@@ -205,7 +205,7 @@
if (values != null) {
try {
return HttpDate.parse(values[0]);
- } on Exception catch (e) {
+ } on Exception {
return null;
}
}
@@ -224,7 +224,7 @@
if (values != null) {
try {
return HttpDate.parse(values[0]);
- } on Exception catch (e) {
+ } on Exception {
return null;
}
}
@@ -243,7 +243,7 @@
if (values != null) {
try {
return HttpDate.parse(values[0]);
- } on Exception catch (e) {
+ } on Exception {
return null;
}
}
@@ -399,7 +399,7 @@
} else {
try {
_port = int.parse(value.substring(pos + 1));
- } on FormatException catch (e) {
+ } on FormatException {
_port = null;
}
}
@@ -888,14 +888,6 @@
return s.substring(start, index).trim();
}
- void expect(String expected) {
- if (done()) throw new HttpException("Failed to parse header value [$s]");
- if (s[index] != expected) {
- throw new HttpException("Failed to parse header value [$s]");
- }
- index++;
- }
-
void parseAttributes() {
String parseAttributeName() {
int start = index;
diff --git a/sdk/lib/_http/http_impl.dart b/sdk/lib/_http/http_impl.dart
index caf1d44..336c6d0 100644
--- a/sdk/lib/_http/http_impl.dart
+++ b/sdk/lib/_http/http_impl.dart
@@ -2628,7 +2628,6 @@
bool get _isActive => _state == _ACTIVE;
bool get _isIdle => _state == _IDLE;
bool get _isClosing => _state == _CLOSING;
- bool get _isDetached => _state == _DETACHED;
String get _serviceTypePath => 'io/http/serverconnections';
String get _serviceTypeName => 'HttpServerConnection';
@@ -2970,7 +2969,7 @@
int port;
try {
port = int.parse(portString);
- } on FormatException catch (e) {
+ } on FormatException {
throw new HttpException(
"Invalid proxy configuration $configuration, "
"invalid port '$portString'");
@@ -3270,7 +3269,6 @@
String qop;
String cnonce;
String nc;
- var x;
hasher = new _MD5()..add(credentials.ha1.codeUnits)..add([_CharCode.COLON]);
if (credentials.qop == "auth") {
qop = credentials.qop;
diff --git a/sdk/lib/_http/http_parser.dart b/sdk/lib/_http/http_parser.dart
index 8ef7ab0..8d64a50 100644
--- a/sdk/lib/_http/http_parser.dart
+++ b/sdk/lib/_http/http_parser.dart
@@ -972,7 +972,7 @@
return true;
}
- int _expect(int val1, int val2) {
+ void _expect(int val1, int val2) {
if (val1 != val2) {
throw new HttpException("Failed to parse HTTP");
}
diff --git a/sdk/lib/_http/websocket.dart b/sdk/lib/_http/websocket.dart
index 1d27852..77b5008 100644
--- a/sdk/lib/_http/websocket.dart
+++ b/sdk/lib/_http/websocket.dart
@@ -145,8 +145,7 @@
throw new ArgumentError("Illegal 0 padding on value.");
} else {
mwb = serverMaxWindowBits == null
- ? int.parse(part,
- onError: (source) => _WebSocketImpl.DEFAULT_WINDOW_BITS)
+ ? int.tryParse(part) ?? _WebSocketImpl.DEFAULT_WINDOW_BITS
: serverMaxWindowBits;
info.headerValue = "; server_max_window_bits=${mwb}";
info.maxWindowBits = mwb;
@@ -335,7 +334,7 @@
* Set and get the interval for sending ping signals. If a ping message is not
* answered by a pong message from the peer, the `WebSocket` is assumed
* disconnected and the connection is closed with a
- * [WebSocketStatus.GOING_AWAY] close code. When a ping signal is sent, the
+ * [WebSocketStatus.goingAway] close code. When a ping signal is sent, the
* pong message must be received within [pingInterval].
*
* There are never two outstanding pings at any given time, and the next ping
@@ -451,7 +450,7 @@
/**
* Closes the WebSocket connection. Set the optional [code] and [reason]
* arguments to send close information to the remote peer. If they are
- * omitted, the peer will see [WebSocketStatus.NO_STATUS_RECEIVED] code
+ * omitted, the peer will see [WebSocketStatus.noStatusReceived] code
* with no reason.
*/
Future close([int code, String reason]);
diff --git a/sdk/lib/_http/websocket_impl.dart b/sdk/lib/_http/websocket_impl.dart
index d93f366..35ee68b 100644
--- a/sdk/lib/_http/websocket_impl.dart
+++ b/sdk/lib/_http/websocket_impl.dart
@@ -91,7 +91,7 @@
int _remainingPayloadBytes = -1;
int _unmaskingIndex = 0;
int _currentMessageType = _WebSocketMessageType.NONE;
- int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
+ int closeCode = WebSocketStatus.noStatusReceived;
String closeReason = "";
EventSink<dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ > _eventSink;
@@ -348,14 +348,14 @@
void _controlFrameEnd() {
switch (_opcode) {
case _WebSocketOpcode.CLOSE:
- closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
+ closeCode = WebSocketStatus.noStatusReceived;
var payload = _payload.takeBytes();
if (payload.length > 0) {
if (payload.length == 1) {
throw new WebSocketException("Protocol error");
}
closeCode = payload[0] << 8 | payload[1];
- if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) {
+ if (closeCode == WebSocketStatus.noStatusReceived) {
throw new WebSocketException("Protocol error");
}
if (payload.length > 2) {
@@ -1112,7 +1112,7 @@
return DEFAULT_WINDOW_BITS;
}
- return int.parse(o, onError: (s) => DEFAULT_WINDOW_BITS);
+ return int.tryParse(o) ?? DEFAULT_WINDOW_BITS;
}
return new _WebSocketPerMessageDeflate(
@@ -1146,9 +1146,9 @@
}, onError: (error, stackTrace) {
if (_closeTimer != null) _closeTimer.cancel();
if (error is FormatException) {
- _close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA);
+ _close(WebSocketStatus.invalidFramePayloadData);
} else {
- _close(WebSocketStatus.PROTOCOL_ERROR);
+ _close(WebSocketStatus.protocolError);
}
// An error happened, set the close code set above.
_closeCode = _outCloseCode;
@@ -1204,7 +1204,7 @@
_consumer.add(new _WebSocketPing());
_pingTimer = new Timer(_pingInterval, () {
// No pong received.
- _close(WebSocketStatus.GOING_AWAY);
+ _close(WebSocketStatus.goingAway);
});
});
}
@@ -1309,12 +1309,12 @@
static bool _isReservedStatusCode(int code) {
return code != null &&
- (code < WebSocketStatus.NORMAL_CLOSURE ||
- code == WebSocketStatus.RESERVED_1004 ||
- code == WebSocketStatus.NO_STATUS_RECEIVED ||
- code == WebSocketStatus.ABNORMAL_CLOSURE ||
- (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
- code < WebSocketStatus.RESERVED_1015) ||
- (code >= WebSocketStatus.RESERVED_1015 && code < 3000));
+ (code < WebSocketStatus.normalClosure ||
+ code == WebSocketStatus.reserved1004 ||
+ code == WebSocketStatus.noStatusReceived ||
+ code == WebSocketStatus.abnormalClosure ||
+ (code > WebSocketStatus.internalServerError &&
+ code < WebSocketStatus.reserved1015) ||
+ (code >= WebSocketStatus.reserved1015 && code < 3000));
}
}
diff --git a/sdk/lib/_internal/js_dev_runtime/libraries.dart b/sdk/lib/_internal/js_dev_runtime/libraries.dart
index b844996..283133c 100644
--- a/sdk/lib/_internal/js_dev_runtime/libraries.dart
+++ b/sdk/lib/_internal/js_dev_runtime/libraries.dart
@@ -86,10 +86,11 @@
categories: "Client,Server",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
- "js": const LibraryInfo("js/dart2js/js_dart2js.dart",
+ "js": const LibraryInfo("js/js.dart",
categories: "Client",
maturity: Maturity.STABLE,
- platforms: DART2JS_PLATFORM),
+ platforms: DART2JS_PLATFORM,
+ dart2jsPatchPath: "_internal/js_runtime/lib/js_patch.dart"),
"js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
categories: "Client",
maturity: Maturity.STABLE,
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart
new file mode 100644
index 0000000..e0c10e8
--- /dev/null
+++ b/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart
@@ -0,0 +1,443 @@
+// 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.6
+
+// Patch file for dart:js library.
+library dart.js;
+
+import 'dart:collection' show HashMap, ListMixin;
+
+import 'dart:_js_helper' show patch, Primitives;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+@patch
+JsObject get context => _context;
+
+final JsObject _context = _wrapToDart(dart.global_);
+
+@patch
+class JsObject {
+ // The wrapped JS object.
+ final dynamic _jsObject;
+
+ // This should only be called from _wrapToDart
+ JsObject._fromJs(this._jsObject) {
+ assert(_jsObject != null);
+ }
+
+ @patch
+ factory JsObject(JsFunction constructor, [List arguments]) {
+ var ctor = constructor._jsObject;
+ if (arguments == null) {
+ return _wrapToDart(JS('', 'new #()', ctor));
+ }
+ var unwrapped = List.from(arguments.map(_convertToJS));
+ return _wrapToDart(JS('', 'new #(...#)', ctor, unwrapped));
+ }
+
+ @patch
+ factory JsObject.fromBrowserObject(object) {
+ if (object is num || object is String || object is bool || object == null) {
+ throw ArgumentError("object cannot be a num, string, bool, or null");
+ }
+ return _wrapToDart(_convertToJS(object));
+ }
+
+ @patch
+ factory JsObject.jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw ArgumentError("object must be a Map or Iterable");
+ }
+ return _wrapToDart(_convertDataTree(object));
+ }
+
+ static _convertDataTree(data) {
+ var _convertedObjects = HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('', '#[#] = #', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return _convertToJS(o);
+ }
+ }
+
+ return _convert(data);
+ }
+
+ @patch
+ dynamic operator [](Object property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ return _convertToDart(JS('', '#[#]', _jsObject, property));
+ }
+
+ @patch
+ void operator []=(Object property, value) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
+ }
+
+ @patch
+ bool operator ==(other) =>
+ other is JsObject && JS<bool>('!', '# === #', _jsObject, other._jsObject);
+
+ @patch
+ bool hasProperty(property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ return JS<bool>('!', '# in #', property, _jsObject);
+ }
+
+ @patch
+ void deleteProperty(property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ JS<bool>('!', 'delete #[#]', _jsObject, property);
+ }
+
+ @patch
+ bool instanceof(JsFunction type) {
+ return JS<bool>('!', '# instanceof #', _jsObject, _convertToJS(type));
+ }
+
+ @patch
+ String toString() {
+ try {
+ return JS<String>('!', 'String(#)', _jsObject);
+ } catch (e) {
+ return super.toString();
+ }
+ }
+
+ @patch
+ dynamic callMethod(method, [List args]) {
+ if (method is! String && method is! num) {
+ throw ArgumentError("method is not a String or num");
+ }
+ if (args != null) args = List.from(args.map(_convertToJS));
+ var fn = JS('', '#[#]', _jsObject, method);
+ if (JS<bool>('!', 'typeof(#) !== "function"', fn)) {
+ throw NoSuchMethodError(_jsObject, Symbol(method), args, {});
+ }
+ return _convertToDart(JS('', '#.apply(#, #)', fn, _jsObject, args));
+ }
+}
+
+@patch
+class JsFunction extends JsObject {
+ @patch
+ factory JsFunction.withThis(Function f) {
+ return JsFunction._fromJs(JS(
+ '',
+ 'function(/*...arguments*/) {'
+ ' let args = [#(this)];'
+ ' for (let arg of arguments) {'
+ ' args.push(#(arg));'
+ ' }'
+ ' return #(#(...args));'
+ '}',
+ _convertToDart,
+ _convertToDart,
+ _convertToJS,
+ f));
+ }
+
+ JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
+
+ @patch
+ dynamic apply(List args, {thisArg}) => _convertToDart(JS(
+ '',
+ '#.apply(#, #)',
+ _jsObject,
+ _convertToJS(thisArg),
+ args == null ? null : List.from(args.map(_convertToJS))));
+}
+
+// TODO(jmesserly): this is totally unnecessary in dev_compiler.
+@patch
+class JsArray<E> extends JsObject with ListMixin<E> {
+ @patch
+ factory JsArray() => JsArray<E>._fromJs([]);
+
+ @patch
+ factory JsArray.from(Iterable<E> other) =>
+ JsArray<E>._fromJs([]..addAll(other.map(_convertToJS)));
+
+ JsArray._fromJs(jsObject) : super._fromJs(jsObject);
+
+ _checkIndex(int index) {
+ if (index is int && (index < 0 || index >= length)) {
+ throw RangeError.range(index, 0, length);
+ }
+ }
+
+ _checkInsertIndex(int index) {
+ if (index is int && (index < 0 || index >= length + 1)) {
+ throw RangeError.range(index, 0, length);
+ }
+ }
+
+ static _checkRange(int start, int end, int length) {
+ if (start < 0 || start > length) {
+ throw RangeError.range(start, 0, length);
+ }
+ if (end < start || end > length) {
+ throw RangeError.range(end, start, length);
+ }
+ }
+
+ @patch
+ E operator [](Object index) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ return super[index] as E;
+ }
+
+ @patch
+ void operator []=(Object index, value) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ super[index] = value;
+ }
+
+ @patch
+ int get length {
+ // Check the length honours the List contract.
+ var len = JS('', '#.length', _jsObject);
+ // JavaScript arrays have lengths which are unsigned 32-bit integers.
+ if (JS<bool>(
+ '!', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
+ return JS<int>('!', '#', len);
+ }
+ throw StateError('Bad JsArray length');
+ }
+
+ @patch
+ void set length(int length) {
+ super['length'] = length;
+ }
+
+ @patch
+ void add(E value) {
+ callMethod('push', [value]);
+ }
+
+ @patch
+ void addAll(Iterable<E> iterable) {
+ var list = (JS<bool>('!', '# instanceof Array', iterable))
+ ? iterable
+ : List.from(iterable);
+ callMethod('push', list);
+ }
+
+ @patch
+ void insert(int index, E element) {
+ _checkInsertIndex(index);
+ callMethod('splice', [index, 0, element]);
+ }
+
+ @patch
+ E removeAt(int index) {
+ _checkIndex(index);
+ return callMethod('splice', [index, 1])[0] as E;
+ }
+
+ @patch
+ E removeLast() {
+ if (length == 0) throw RangeError(-1);
+ return callMethod('pop') as E;
+ }
+
+ @patch
+ void removeRange(int start, int end) {
+ _checkRange(start, end, length);
+ callMethod('splice', [start, end - start]);
+ }
+
+ @patch
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ _checkRange(start, end, this.length);
+ int length = end - start;
+ if (length == 0) return;
+ if (skipCount < 0) throw ArgumentError(skipCount);
+ var args = <Object>[start, length]
+ ..addAll(iterable.skip(skipCount).take(length));
+ callMethod('splice', args);
+ }
+
+ @patch
+ void sort([int compare(E a, E b)]) {
+ // Note: arr.sort(null) is a type error in FF
+ callMethod('sort', compare == null ? [] : [compare]);
+ }
+}
+
+// Cross frame objects should not be considered browser types.
+// We include the instanceof Object test to filter out cross frame objects
+// on FireFox. Surprisingly on FireFox the instanceof Window test succeeds for
+// cross frame windows while the instanceof Object test fails.
+bool _isBrowserType(o) => JS(
+ 'bool',
+ '# instanceof Object && ('
+ '# instanceof Blob || '
+ '# instanceof Event || '
+ '(window.KeyRange && # instanceof KeyRange) || '
+ '(window.IDBKeyRange && # instanceof IDBKeyRange) || '
+ '# instanceof ImageData || '
+ '# instanceof Node || '
+ // Int8Array.__proto__ is TypedArray.
+ '(window.Int8Array && # instanceof Int8Array.__proto__) || '
+ '# instanceof Window)',
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o);
+
+class _DartObject {
+ final _dartObj;
+ _DartObject(this._dartObj);
+}
+
+dynamic _convertToJS(dynamic o) {
+ if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+ return o;
+ } else if (o is DateTime) {
+ return Primitives.lazyAsJsDate(o);
+ } else if (o is JsObject) {
+ return o._jsObject;
+ } else if (o is Function) {
+ return _putIfAbsent(_jsProxies, o, _wrapDartFunction);
+ } else {
+ // TODO(jmesserly): for now, we wrap other objects, to keep compatibility
+ // with the original dart:js behavior.
+ return _putIfAbsent(_jsProxies, o, (o) => _DartObject(o));
+ }
+}
+
+dynamic _wrapDartFunction(f) {
+ var wrapper = JS(
+ '',
+ 'function(/*...arguments*/) {'
+ ' let args = Array.prototype.map.call(arguments, #);'
+ ' return #(#(...args));'
+ '}',
+ _convertToDart,
+ _convertToJS,
+ f);
+ JS('', '#.set(#, #)', _dartProxies, wrapper, f);
+
+ return wrapper;
+}
+
+// converts a Dart object to a reference to a native JS object
+// which might be a DartObject JS->Dart proxy
+Object _convertToDart(o) {
+ if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+ return o;
+ } else if (JS('!', '# instanceof Date', o)) {
+ num ms = JS('!', '#.getTime()', o);
+ return DateTime.fromMillisecondsSinceEpoch(ms);
+ } else if (o is _DartObject &&
+ !identical(dart.getReifiedType(o), dart.jsobject)) {
+ return o._dartObj;
+ } else {
+ return _wrapToDart(o);
+ }
+}
+
+Object _wrapToDart(o) => _putIfAbsent(_dartProxies, o, _wrapToDartHelper);
+
+Object _wrapToDartHelper(o) {
+ if (JS<bool>('!', 'typeof # == "function"', o)) {
+ return JsFunction._fromJs(o);
+ }
+ if (JS<bool>('!', '# instanceof Array', o)) {
+ return JsArray._fromJs(o);
+ }
+ return JsObject._fromJs(o);
+}
+
+final _dartProxies = JS('', 'new WeakMap()');
+final _jsProxies = JS('', 'new WeakMap()');
+
+Object _putIfAbsent(weakMap, o, getValue(o)) {
+ var value = JS('', '#.get(#)', weakMap, o);
+ if (value == null) {
+ value = getValue(o);
+ JS('', '#.set(#, #)', weakMap, o, value);
+ }
+ return value;
+}
+
+Expando<Function> _interopExpando = Expando<Function>();
+
+@patch
+F allowInterop<F extends Function>(F f) {
+ if (!dart.isDartFunction(f)) return f;
+ var ret = _interopExpando[f];
+ if (ret == null) {
+ ret = JS(
+ '',
+ 'function (...args) {'
+ ' return #(#, args);'
+ '}',
+ dart.dcall,
+ f);
+ _interopExpando[f] = ret;
+ }
+ return ret;
+}
+
+Expando<Function> _interopCaptureThisExpando = Expando<Function>();
+
+@patch
+Function allowInteropCaptureThis(Function f) {
+ if (!dart.isDartFunction(f)) return f;
+ var ret = _interopCaptureThisExpando[f];
+ if (ret == null) {
+ ret = JS(
+ '',
+ 'function(...arguments) {'
+ ' let args = [this];'
+ ' args.push.apply(args, arguments);'
+ ' return #(#, args);'
+ '}',
+ dart.dcall,
+ f);
+ _interopCaptureThisExpando[f] = ret;
+ }
+ return ret;
+}
diff --git a/sdk_nnbd/lib/js/dart2js/js_dart2js.dart b/sdk/lib/_internal/js_runtime/lib/js_patch.dart
similarity index 67%
rename from sdk_nnbd/lib/js/dart2js/js_dart2js.dart
rename to sdk/lib/_internal/js_runtime/lib/js_patch.dart
index 4155113..ab4a332 100644
--- a/sdk_nnbd/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_patch.dart
@@ -1,109 +1,22 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// 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
+// @dart = 2.6
-/// Low-level support for interoperating with JavaScript.
-///
-/// You should usually use `package:js` instead of this library. For more
-/// information, see the [JS interop page](https://dart.dev/web/js-interop).
-///
-/// This library provides access to JavaScript objects from Dart, allowing
-/// Dart code to get and set properties, and call methods of JavaScript objects
-/// and invoke JavaScript functions. The library takes care of converting
-/// between Dart and JavaScript objects where possible, or providing proxies if
-/// conversion isn't possible.
-///
-/// This library does not make Dart objects usable from JavaScript, their
-/// methods and properties are not accessible, though it does allow Dart
-/// functions to be passed into and called from JavaScript.
-///
-/// [JsObject] is the core type and represents a proxy of a JavaScript object.
-/// JsObject gives access to the underlying JavaScript objects properties and
-/// methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
-/// created from proxies to JavaScript constructors.
-///
-/// The top-level getter [context] provides a [JsObject] that represents the
-/// global object in JavaScript, usually `window`.
-///
-/// The following example shows an alert dialog via a JavaScript call to the
-/// global function `alert()`:
-///
-/// import 'dart:js';
-///
-/// main() => context.callMethod('alert', ['Hello from Dart!']);
-///
-/// This example shows how to create a [JsObject] from a JavaScript constructor
-/// and access its properties:
-///
-/// import 'dart:js';
-///
-/// main() {
-/// var object = JsObject(context['Object']);
-/// object['greeting'] = 'Hello';
-/// object['greet'] = (name) => "${object['greeting']} $name";
-/// var message = object.callMethod('greet', ['JavaScript']);
-/// context['console'].callMethod('log', [message]);
-/// }
-///
-/// ## Proxying and automatic conversion
-///
-/// When setting properties on a JsObject or passing arguments to a Javascript
-/// method or function, Dart objects are automatically converted or proxied to
-/// JavaScript objects. When accessing JavaScript properties, or when a Dart
-/// closure is invoked from JavaScript, the JavaScript objects are also
-/// converted to Dart.
-///
-/// Functions and closures are proxied in such a way that they are callable. A
-/// Dart closure assigned to a JavaScript property is proxied by a function in
-/// JavaScript. A JavaScript function accessed from Dart is proxied by a
-/// [JsFunction], which has a [apply] method to invoke it.
-///
-/// The following types are transferred directly and not proxied:
-///
-/// * Basic types: `null`, `bool`, `num`, `String`, `DateTime`
-/// * `TypedData`, including its subclasses like `Int32List`, but _not_
-/// `ByteBuffer`
-/// * When compiling for the web, also: `Blob`, `Event`, `ImageData`,
-/// `KeyRange`, `Node`, and `Window`.
-///
-/// ## Converting collections with JsObject.jsify()
-///
-/// To create a JavaScript collection from a Dart collection use the
-/// [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
-/// into JavaScript Objects and Arrays.
-///
-/// The following expression creates a new JavaScript object with the properties
-/// `a` and `b` defined:
-///
-/// var jsMap = JsObject.jsify({'a': 1, 'b': 2});
-///
-/// This expression creates a JavaScript array:
-///
-/// var jsArray = JsObject.jsify([1, 2, 3]);
-///
-/// {@category Web}
-library dart.js;
-
+// Patch file for dart:js library.
import 'dart:collection' show HashMap, ListMixin;
import 'dart:typed_data' show TypedData;
-import 'dart:_foreign_helper' show JS, JS_CONST, DART_CLOSURE_TO_JS;
-import 'dart:_interceptors'
- show
- JavaScriptFunction,
- JavaScriptObject,
- UnknownJavaScriptObject,
- DART_CLOSURE_PROPERTY_NAME;
-import 'dart:_js_helper'
- show Primitives, convertDartClosureToJS, getIsolateAffinityTag;
+import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS;
+import 'dart:_interceptors' show JavaScriptFunction, DART_CLOSURE_PROPERTY_NAME;
+import 'dart:_js_helper' show patch, Primitives, getIsolateAffinityTag;
import 'dart:_js' show isBrowserObject, convertFromBrowserObject;
-export 'dart:_interceptors' show JavaScriptObject;
+@patch
+JsObject get context => _context;
-/// The JavaScript global object, usually `window`.
-final JsObject context = _wrapToDart(JS('', 'self'));
+final JsObject _context = _wrapToDart(JS('', 'self'));
_convertDartFunction(Function f, {bool captureThis: false}) {
return JS(
@@ -129,10 +42,7 @@
return _convertToJS(Function.apply(callback, dartArgs));
}
-/// A proxy on a JavaScript object.
-///
-/// The properties of the JavaScript object are accessible via the `[]` and
-/// `[]=` operators. Methods are callable via [callMethod].
+@patch
class JsObject {
// The wrapped JS object.
final dynamic _jsObject;
@@ -142,8 +52,7 @@
assert(_jsObject != null);
}
- /// Constructs a JavaScript object from its native [constructor] and returns
- /// a proxy to it.
+ @patch
factory JsObject(JsFunction constructor, [List arguments]) {
var ctor = _convertToJS(constructor);
if (arguments == null) {
@@ -206,15 +115,7 @@
// return _wrapToDart(jsObj);
}
- /// Constructs a [JsObject] that proxies a native Dart object; _for expert use
- /// only_.
- ///
- /// Use this constructor only if you wish to get access to JavaScript
- /// properties attached to a browser host object, such as a Node or Blob, that
- /// is normally automatically converted into a native Dart object.
- ///
- /// An exception will be thrown if [object] either is `null` or has the type
- /// `bool`, `num`, or `String`.
+ @patch
factory JsObject.fromBrowserObject(object) {
if (object is num || object is String || object is bool || object == null) {
throw ArgumentError("object cannot be a num, string, bool, or null");
@@ -222,13 +123,7 @@
return _wrapToDart(_convertToJS(object));
}
- /// Recursively converts a JSON-like collection of Dart objects to a
- /// collection of JavaScript objects and returns a [JsObject] proxy to it.
- ///
- /// [object] must be a [Map] or [Iterable], the contents of which are also
- /// converted. Maps and Iterables are copied to a new JavaScript object.
- /// Primitives and other transferable values are directly converted to their
- /// JavaScript type, and all other objects are proxied.
+ @patch
factory JsObject.jsify(object) {
if ((object is! Map) && (object is! Iterable)) {
throw ArgumentError("object must be a Map or Iterable");
@@ -263,10 +158,7 @@
return _convert(data);
}
- /// Returns the value associated with [property] from the proxied JavaScript
- /// object.
- ///
- /// The type of [property] must be either [String] or [num].
+ @patch
dynamic operator [](property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -274,10 +166,7 @@
return _convertToDart(JS('', '#[#]', _jsObject, property));
}
- // Sets the value associated with [property] on the proxied JavaScript
- // object.
- //
- // The type of [property] must be either [String] or [num].
+ @patch
void operator []=(property, value) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -285,15 +174,11 @@
JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
}
- int get hashCode => 0;
-
+ @patch
bool operator ==(other) =>
other is JsObject && JS('bool', '# === #', _jsObject, other._jsObject);
- /// Returns `true` if the JavaScript object contains the specified property
- /// either directly or though its prototype chain.
- ///
- /// This is the equivalent of the `in` operator in JavaScript.
+ @patch
bool hasProperty(property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -301,9 +186,7 @@
return JS('bool', '# in #', property, _jsObject);
}
- /// Removes [property] from the JavaScript object.
- ///
- /// This is the equivalent of the `delete` operator in JavaScript.
+ @patch
void deleteProperty(property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -311,14 +194,12 @@
JS('bool', 'delete #[#]', _jsObject, property);
}
- /// Returns `true` if the JavaScript object has [type] in its prototype chain.
- ///
- /// This is the equivalent of the `instanceof` operator in JavaScript.
+ @patch
bool instanceof(JsFunction type) {
return JS('bool', '# instanceof #', _jsObject, _convertToJS(type));
}
- /// Returns the result of the JavaScript objects `toString` method.
+ @patch
String toString() {
try {
return JS('String', 'String(#)', _jsObject);
@@ -327,10 +208,7 @@
}
}
- /// Calls [method] on the JavaScript object with the arguments [args] and
- /// returns the result.
- ///
- /// The type of [method] must be either [String] or [num].
+ @patch
dynamic callMethod(method, [List args]) {
if (method is! String && method is! num) {
throw ArgumentError("method is not a String or num");
@@ -340,10 +218,9 @@
}
}
-/// A proxy on a JavaScript Function object.
+@patch
class JsFunction extends JsObject {
- /// Returns a [JsFunction] that captures its 'this' binding and calls [f]
- /// with the value of JavaScript `this` passed as the first argument.
+ @patch
factory JsFunction.withThis(Function f) {
var jsFunc = _convertDartFunction(f, captureThis: true);
return JsFunction._fromJs(jsFunc);
@@ -351,8 +228,7 @@
JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
- /// Invokes the JavaScript function with arguments [args]. If [thisArg] is
- /// supplied it is the value of `this` for the invocation.
+ @patch
dynamic apply(List args, {thisArg}) => _convertToDart(JS(
'',
'#.apply(#, #)',
@@ -361,15 +237,14 @@
args == null ? null : List.from(args.map(_convertToJS))));
}
-/// A [List] that proxies a JavaScript array.
+@patch
class JsArray<E> extends JsObject with ListMixin<E> {
- /// Creates an empty JavaScript array.
- JsArray() : super._fromJs([]);
+ @patch
+ factory JsArray() => JsArray<E>._fromJs([]);
- /// Creates a new JavaScript array and initializes it to the contents of
- /// [other].
- JsArray.from(Iterable<E> other)
- : super._fromJs([]..addAll(other.map(_convertToJS)));
+ @patch
+ factory JsArray.from(Iterable<E> other) =>
+ JsArray<E>._fromJs([]..addAll(other.map(_convertToJS)));
JsArray._fromJs(jsObject) : super._fromJs(jsObject);
@@ -396,6 +271,7 @@
// Methods required by ListMixin
+ @patch
E operator [](dynamic index) {
// TODO(justinfagnani): fix the semantics for non-ints
// dartbug.com/14605
@@ -405,6 +281,7 @@
return super[index];
}
+ @patch
void operator []=(dynamic index, E value) {
// TODO(justinfagnani): fix the semantics for non-ints
// dartbug.com/14605
@@ -414,6 +291,7 @@
super[index] = value;
}
+ @patch
int get length {
// Check the length honours the List contract.
var len = JS('', '#.length', _jsObject);
@@ -424,16 +302,19 @@
throw StateError('Bad JsArray length');
}
+ @patch
void set length(int length) {
super['length'] = length;
}
// Methods overridden for better performance
+ @patch
void add(E value) {
callMethod('push', [value]);
}
+ @patch
void addAll(Iterable<E> iterable) {
var list = (JS('bool', '# instanceof Array', iterable))
? iterable
@@ -441,26 +322,31 @@
callMethod('push', list);
}
+ @patch
void insert(int index, E element) {
_checkInsertIndex(index);
callMethod('splice', [index, 0, element]);
}
+ @patch
E removeAt(int index) {
_checkIndex(index);
return callMethod('splice', [index, 1])[0];
}
+ @patch
E removeLast() {
if (length == 0) throw RangeError(-1);
return callMethod('pop');
}
+ @patch
void removeRange(int start, int end) {
_checkRange(start, end, length);
callMethod('splice', [start, end - start]);
}
+ @patch
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_checkRange(start, end, this.length);
int length = end - start;
@@ -471,6 +357,7 @@
callMethod('splice', args);
}
+ @patch
void sort([int compare(E a, E b)]) {
// Note: arr.sort(null) is a type error in FF
callMethod('sort', compare == null ? [] : [compare]);
@@ -659,17 +546,7 @@
return Function.apply(callback, [self]..addAll(arguments));
}
-/// Returns a wrapper around function [f] that can be called from JavaScript
-/// using `package:js` JavaScript interop.
-///
-/// The calling conventions in Dart2Js differ from JavaScript and so, by
-/// default, it is not possible to call a Dart function directly. Wrapping with
-/// `allowInterop` creates a function that can be called from JavaScript or
-/// Dart. The semantics of the wrapped function are still more strict than
-/// JavaScript, and the function will throw if called with too many or too few
-/// arguments.
-///
-/// Calling this method repeatedly on a function will return the same result.
+@patch
F allowInterop<F extends Function>(F f) {
if (JS('bool', 'typeof(#) == "function"', f)) {
// Already supports interop, just use the existing function.
@@ -679,13 +556,7 @@
}
}
-/// Returns a wrapper around function [f] that can be called from JavaScript
-/// using `package:js` JavaScript interop, passing JavaScript `this` as the first
-/// argument.
-///
-/// See [allowInterop].
-///
-/// When called from Dart, [null] will be passed as the first argument.
+@patch
Function allowInteropCaptureThis(Function f) {
if (JS('bool', 'typeof(#) == "function"', f)) {
// Behavior when the function is already a JS function is unspecified.
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index e8316e1..78c275d 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -16,7 +16,6 @@
JS_EMBEDDED_GLOBAL,
JS_GET_FLAG,
JS_GET_NAME,
- JS_STRING_CONCAT,
RAW_DART_FUNCTION_REF,
TYPE_REF;
@@ -789,7 +788,8 @@
var isFn = RAW_DART_FUNCTION_REF(_generalIsTestImplementation);
- if (isTopType(testRti)) {
+ // TODO(fishythefish): Update for NNBD.
+ if (isLegacyTopType(testRti)) {
isFn = RAW_DART_FUNCTION_REF(_isTop);
var asFn = RAW_DART_FUNCTION_REF(_asTop);
Rti._setAsCheckFunction(testRti, asFn);
@@ -811,7 +811,11 @@
String name = Rti._getInterfaceName(testRti);
var arguments = Rti._getInterfaceTypeArguments(testRti);
if (JS(
- 'bool', '#.every(#)', arguments, RAW_DART_FUNCTION_REF(isTopType))) {
+ 'bool',
+ '#.every(#)',
+ arguments,
+ // TODO(fishythefish): Update for NNBD.
+ RAW_DART_FUNCTION_REF(isLegacyTopType))) {
String propertyName =
'${JS_GET_NAME(JsGetName.OPERATOR_IS_PREFIX)}${name}';
Rti._setSpecializedTestResource(testRti, propertyName);
@@ -830,7 +834,8 @@
// method. The Rti object is 'this'.
Rti testRti = _castToRti(JS('', 'this'));
Rti objectRti = instanceOrFunctionType(object, testRti);
- return isSubtype(_theUniverse(), objectRti, testRti);
+ // TODO(fishythefish): Update for NNBD.
+ return isLegacySubtype(_theUniverse(), objectRti, testRti);
}
/// Called from generated code.
@@ -881,7 +886,8 @@
/// Called from generated code.
checkTypeBound(Rti type, Rti bound, variable, methodName) {
- if (isSubtype(_theUniverse(), type, bound)) return type;
+ // TODO(fishythefish): Update for NNBD.
+ if (isLegacySubtype(_theUniverse(), type, bound)) return type;
String message = "The type argument '${_rtiToString(type, null)}' is not"
" a subtype of the type variable bound '${_rtiToString(bound, null)}'"
" of type variable '${_Utils.asString(variable)}' in '$methodName'.";
@@ -1080,7 +1086,8 @@
typeParametersText += typeSep;
typeParametersText += genericContext[genericContext.length - 1 - i];
Rti boundRti = _castToRti(_Utils.arrayAt(bounds, i));
- if (!isTopType(boundRti)) {
+ // TODO(fishythefish): Update for NNBD.
+ if (!isLegacyTopType(boundRti)) {
typeParametersText +=
' extends ' + _rtiToString(boundRti, genericContext);
}
@@ -1470,7 +1477,6 @@
environment = Rti._getBindingBase(environment);
}
- assert(kind == Rti.kindInterface);
String interfaceName = Rti._getInterfaceName(environment);
Object rule = _Universe.findRule(universe, interfaceName);
assert(rule != null);
@@ -2310,49 +2316,63 @@
// -------- Subtype tests ------------------------------------------------------
// Future entry point from compiled code.
-bool isSubtype(universe, Rti s, Rti t) {
- return _isSubtype(universe, s, null, t, null);
+bool isLegacySubtype(universe, Rti s, Rti t) {
+ return _isSubtype(universe, s, null, t, null, true);
}
-bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
- // Based on
- // https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
- // and https://github.com/dart-lang/language/pull/388.
- // In particular, the bulk of the structure is derived from the former
- // resource, with a few adaptations taken from the latter.
- // - We freely skip subcases which would have already been handled by a
- // previous case.
- // - Some rules are reordered in conjunction with the previous point to reduce
- // the amount of casework.
- // - Left Type Variable Bound in particular is split into two pieces: an
- // optimistic check performed early in the algorithm to reduce the number of
- // backtracking cases when a union appears on the right, and a pessimistic
- // check performed at the usual place in order to completely eliminate the
- // case.
- // - Function type rules are applied before interface type rules.
+bool isNnbdSubtype(universe, Rti s, Rti t) {
+ return _isSubtype(universe, s, null, t, null, false);
+}
+/// Based on
+/// https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
+/// and https://github.com/dart-lang/language/pull/388.
+/// In particular, the bulk of the structure is derived from the former
+/// resource, with a few adaptations taken from the latter.
+/// - We freely skip subcases which would have already been handled by a
+/// previous case.
+/// - Some rules are reordered in conjunction with the previous point to reduce
+/// the amount of casework.
+/// - Left Type Variable Bound in particular is split into two pieces: an
+/// optimistic check performed early in the algorithm to reduce the number of
+/// backtracking cases when a union appears on the right, and a pessimistic
+/// check performed at the usual place in order to completely eliminate the
+/// case.
+/// - Function type rules are applied before interface type rules.
+///
+/// [s] is considered a legacy subtype of [t] if [s] would be a subtype of [t]
+/// in a modification of the NNBD rules in which `?` on types were ignored, `*`
+/// were added to each time, and `required` parameters were treated as
+/// optional. In effect, `Never` is equivalent to `Null`, `Null` is restored to
+/// the bottom of the type hierarchy, `Object` is treated as nullable, and
+/// `required` is ignored on named parameters. This should provide the same
+/// subtyping results as pre-NNBD Dart.
+bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv, bool isLegacy) {
// Reflexivity:
if (_Utils.isIdentical(s, t)) return true;
// Right Top:
- if (isTopType(t)) return true;
+ if (isTopType(t, isLegacy)) return true;
int sKind = Rti._getKind(s);
if (sKind == Rti.kindAny) return true;
// Left Top:
- if (isTopType(s)) return false;
+ if (isTopType(s, isLegacy)) return false;
// Left Bottom:
- // TODO(fishythefish): Update for NNBD - check for `Never` instead of `Null`.
- if (isNullType(s)) return true;
+ if (isLegacy) {
+ if (isNullType(s)) return true;
+ } else {
+ if (sKind == Rti.kindNever) return true;
+ }
// Left Type Variable Bound 1:
bool leftTypeVariable = sKind == Rti.kindGenericFunctionParameter;
if (leftTypeVariable) {
int index = Rti._getGenericFunctionParameterIndex(s);
Rti bound = _castToRti(_Utils.arrayAt(sEnv, index));
- if (_isSubtype(universe, bound, sEnv, t, tEnv)) return true;
+ if (_isSubtype(universe, bound, sEnv, t, tEnv, isLegacy)) return true;
}
int tKind = Rti._getKind(t);
@@ -2360,48 +2380,62 @@
// Left Null:
// Note: Interchanging the Left Null and Right Object rules allows us to
// reduce casework.
- if (isNullType(s)) {
+ if (!isLegacy && isNullType(s)) {
if (tKind == Rti.kindFutureOr) {
- return _isSubtype(universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv);
+ return _isSubtype(
+ universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv, isLegacy);
}
return isNullType(t) || tKind == Rti.kindQuestion || tKind == Rti.kindStar;
}
// Right Object:
- if (isObjectType(t)) {
+ if (!isLegacy && isObjectType(t)) {
if (sKind == Rti.kindFutureOr) {
- return _isSubtype(universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv);
+ return _isSubtype(
+ universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv, isLegacy);
}
if (sKind == Rti.kindStar) {
- return _isSubtype(universe, Rti._getStarArgument(s), sEnv, t, tEnv);
+ return _isSubtype(
+ universe, Rti._getStarArgument(s), sEnv, t, tEnv, isLegacy);
}
return sKind != Rti.kindQuestion;
}
// Left Legacy:
if (sKind == Rti.kindStar) {
- return _isSubtype(universe, Rti._getStarArgument(s), sEnv, t, tEnv);
+ return _isSubtype(
+ universe, Rti._getStarArgument(s), sEnv, t, tEnv, isLegacy);
}
// Right Legacy:
if (tKind == Rti.kindStar) {
return _isSubtype(
- universe, s, sEnv, Rti._getQuestionFromStar(universe, t), tEnv);
+ universe,
+ s,
+ sEnv,
+ isLegacy
+ ? Rti._getStarArgument(t)
+ : Rti._getQuestionFromStar(universe, t),
+ tEnv,
+ isLegacy);
}
// Left FutureOr:
if (sKind == Rti.kindFutureOr) {
- if (!_isSubtype(universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv)) {
+ if (!_isSubtype(
+ universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv, isLegacy)) {
return false;
}
- return _isSubtype(
- universe, Rti._getFutureFromFutureOr(universe, s), sEnv, t, tEnv);
+ return _isSubtype(universe, Rti._getFutureFromFutureOr(universe, s), sEnv,
+ t, tEnv, isLegacy);
}
// Left Nullable:
if (sKind == Rti.kindQuestion) {
- return _isSubtype(universe, TYPE_REF<Null>(), sEnv, t, tEnv) &&
- _isSubtype(universe, Rti._getQuestionArgument(s), sEnv, t, tEnv);
+ return (isLegacy ||
+ _isSubtype(universe, TYPE_REF<Null>(), sEnv, t, tEnv, isLegacy)) &&
+ _isSubtype(
+ universe, Rti._getQuestionArgument(s), sEnv, t, tEnv, isLegacy);
}
// Type Variable Reflexivity 1 is subsumed by Reflexivity and therefore
@@ -2411,17 +2445,20 @@
// Right FutureOr:
if (tKind == Rti.kindFutureOr) {
- if (_isSubtype(universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv)) {
+ if (_isSubtype(
+ universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv, isLegacy)) {
return true;
}
- return _isSubtype(
- universe, s, sEnv, Rti._getFutureFromFutureOr(universe, t), tEnv);
+ return _isSubtype(universe, s, sEnv,
+ Rti._getFutureFromFutureOr(universe, t), tEnv, isLegacy);
}
// Right Nullable:
if (tKind == Rti.kindQuestion) {
- return _isSubtype(universe, s, sEnv, TYPE_REF<Null>(), tEnv) ||
- _isSubtype(universe, s, sEnv, Rti._getQuestionArgument(t), tEnv);
+ return (!isLegacy &&
+ _isSubtype(universe, s, sEnv, TYPE_REF<Null>(), tEnv, isLegacy)) ||
+ _isSubtype(
+ universe, s, sEnv, Rti._getQuestionArgument(t), tEnv, isLegacy);
}
// Left Promoted Variable does not apply at runtime.
@@ -2444,37 +2481,39 @@
var sBounds = Rti._getGenericFunctionBounds(s);
var tBounds = Rti._getGenericFunctionBounds(t);
- if (!typesEqual(sBounds, tBounds)) return false;
+ if (!typesEqual(sBounds, tBounds, isLegacy)) return false;
sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv);
tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv);
return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv,
- Rti._getGenericFunctionBase(t), tEnv);
+ Rti._getGenericFunctionBase(t), tEnv, isLegacy);
}
if (tKind == Rti.kindFunction) {
if (isJsFunctionType(s)) return true;
if (sKind != Rti.kindFunction) return false;
- return _isFunctionSubtype(universe, s, sEnv, t, tEnv);
+ return _isFunctionSubtype(universe, s, sEnv, t, tEnv, isLegacy);
}
// Interface Compositionality + Super-Interface:
if (sKind == Rti.kindInterface) {
if (tKind != Rti.kindInterface) return false;
- return _isInterfaceSubtype(universe, s, sEnv, t, tEnv);
+ return _isInterfaceSubtype(universe, s, sEnv, t, tEnv, isLegacy);
}
return false;
}
// TODO(fishythefish): Support required named parameters.
-bool _isFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+bool _isFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv, bool isLegacy) {
assert(Rti._getKind(s) == Rti.kindFunction);
assert(Rti._getKind(t) == Rti.kindFunction);
Rti sReturnType = Rti._getReturnType(s);
Rti tReturnType = Rti._getReturnType(t);
- if (!_isSubtype(universe, sReturnType, sEnv, tReturnType, tEnv)) return false;
+ if (!_isSubtype(universe, sReturnType, sEnv, tReturnType, tEnv, isLegacy)) {
+ return false;
+ }
_FunctionParameters sParameters = Rti._getFunctionParameters(s);
_FunctionParameters tParameters = Rti._getFunctionParameters(t);
@@ -2501,21 +2540,27 @@
for (int i = 0; i < sRequiredPositionalLength; i++) {
Rti sParameter = _castToRti(_Utils.arrayAt(sRequiredPositional, i));
Rti tParameter = _castToRti(_Utils.arrayAt(tRequiredPositional, i));
- if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv, isLegacy)) {
+ return false;
+ }
}
for (int i = 0; i < requiredPositionalDelta; i++) {
Rti sParameter = _castToRti(_Utils.arrayAt(sOptionalPositional, i));
Rti tParameter = _castToRti(
_Utils.arrayAt(tRequiredPositional, sRequiredPositionalLength + i));
- if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv, isLegacy)) {
+ return false;
+ }
}
for (int i = 0; i < tOptionalPositionalLength; i++) {
Rti sParameter = _castToRti(
_Utils.arrayAt(sOptionalPositional, requiredPositionalDelta + i));
Rti tParameter = _castToRti(_Utils.arrayAt(tOptionalPositional, i));
- if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv, isLegacy)) {
+ return false;
+ }
}
var sOptionalNamed = _FunctionParameters._getOptionalNamed(sParameters);
@@ -2534,13 +2579,13 @@
if (_Utils.stringLessThan(tName, sName)) return false;
Rti sType = _castToRti(_Utils.arrayAt(sOptionalNamed, i - 1));
Rti tType = _castToRti(_Utils.arrayAt(tOptionalNamed, j + 1));
- if (!_isSubtype(universe, tType, tEnv, sType, sEnv)) return false;
+ if (!_isSubtype(universe, tType, tEnv, sType, sEnv, isLegacy)) return false;
}
return true;
}
-bool _isInterfaceSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+bool _isInterfaceSubtype(universe, Rti s, sEnv, Rti t, tEnv, bool isLegacy) {
String sName = Rti._getInterfaceName(s);
String tName = Rti._getInterfaceName(t);
@@ -2569,21 +2614,29 @@
switch (sVariance) {
case Variance.legacyCovariant:
case Variance.covariant:
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) return false;
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv, isLegacy)) {
+ return false;
+ }
break;
case Variance.contravariant:
- if (!_isSubtype(universe, tArg, tEnv, sArg, sEnv)) return false;
+ if (!_isSubtype(universe, tArg, tEnv, sArg, sEnv, isLegacy)) {
+ return false;
+ }
break;
case Variance.invariant:
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv) ||
- !_isSubtype(universe, tArg, tEnv, sArg, sEnv)) return false;
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv, isLegacy) ||
+ !_isSubtype(universe, tArg, tEnv, sArg, sEnv, isLegacy)) {
+ return false;
+ }
break;
default:
throw StateError(
"Unknown variance given for subtype check: $sVariance");
}
} else {
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) return false;
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv, isLegacy)) {
+ return false;
+ }
}
}
return true;
@@ -2610,7 +2663,9 @@
String recipe = _Utils.asString(_Utils.arrayAt(supertypeArgs, i));
Rti supertypeArg = _Universe.evalInEnvironment(universe, s, recipe);
Rti tArg = _castToRti(_Utils.arrayAt(tArgs, i));
- if (!_isSubtype(universe, supertypeArg, sEnv, tArg, tEnv)) return false;
+ if (!_isSubtype(universe, supertypeArg, sEnv, tArg, tEnv, isLegacy)) {
+ return false;
+ }
}
return true;
}
@@ -2620,10 +2675,10 @@
///
/// We ignore renaming of bound type variables because we operate on de Bruijn
/// indices, not names.
-bool typeEqual(Rti s, Rti t) {
+bool typeEqual(Rti s, Rti t, bool isLegacy) {
if (_Utils.isIdentical(s, t)) return true;
- if (isTopType(s)) return isTopType(t);
+ if (isTopType(s, isLegacy)) return isTopType(t, isLegacy);
int sKind = Rti._getKind(s);
int tKind = Rti._getKind(t);
@@ -2633,46 +2688,49 @@
case Rti.kindStar:
case Rti.kindQuestion:
case Rti.kindFutureOr:
- return typeEqual(
- _castToRti(Rti._getPrimary(s)), _castToRti(Rti._getPrimary(t)));
+ return typeEqual(_castToRti(Rti._getPrimary(s)),
+ _castToRti(Rti._getPrimary(t)), isLegacy);
case Rti.kindInterface:
if (Rti._getInterfaceName(s) != Rti._getInterfaceName(t)) return false;
- return typesEqual(
- Rti._getInterfaceTypeArguments(s), Rti._getInterfaceTypeArguments(t));
+ return typesEqual(Rti._getInterfaceTypeArguments(s),
+ Rti._getInterfaceTypeArguments(t), isLegacy);
case Rti.kindBinding:
- return typeEqual(Rti._getBindingBase(s), Rti._getBindingBase(t)) &&
- typesEqual(Rti._getBindingArguments(s), Rti._getBindingArguments(t));
+ return typeEqual(
+ Rti._getBindingBase(s), Rti._getBindingBase(t), isLegacy) &&
+ typesEqual(Rti._getBindingArguments(s), Rti._getBindingArguments(t),
+ isLegacy);
case Rti.kindFunction:
- return typeEqual(Rti._getReturnType(s), Rti._getReturnType(t)) &&
- functionParametersEqual(
- Rti._getFunctionParameters(s), Rti._getFunctionParameters(t));
+ return typeEqual(
+ Rti._getReturnType(s), Rti._getReturnType(t), isLegacy) &&
+ functionParametersEqual(Rti._getFunctionParameters(s),
+ Rti._getFunctionParameters(t), isLegacy);
case Rti.kindGenericFunction:
- return typeEqual(
- Rti._getGenericFunctionBase(s), Rti._getGenericFunctionBase(t)) &&
+ return typeEqual(Rti._getGenericFunctionBase(s),
+ Rti._getGenericFunctionBase(t), isLegacy) &&
typesEqual(Rti._getGenericFunctionBounds(s),
- Rti._getGenericFunctionBounds(t));
+ Rti._getGenericFunctionBounds(t), isLegacy);
default:
return false;
}
}
-bool typesEqual(Object sArray, Object tArray) {
+bool typesEqual(Object sArray, Object tArray, isLegacy) {
int sLength = _Utils.arrayLength(sArray);
int tLength = _Utils.arrayLength(tArray);
if (sLength != tLength) return false;
for (int i = 0; i < sLength; i++) {
if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i)),
- _castToRti(_Utils.arrayAt(tArray, i)))) return false;
+ _castToRti(_Utils.arrayAt(tArray, i)), isLegacy)) return false;
}
return true;
}
-bool namedTypesEqual(Object sArray, Object tArray) {
+bool namedTypesEqual(Object sArray, Object tArray, isLegacy) {
int sLength = _Utils.arrayLength(sArray);
int tLength = _Utils.arrayLength(tArray);
assert(sLength.isEven);
@@ -2682,34 +2740,43 @@
if (_Utils.asString(_Utils.arrayAt(sArray, i)) !=
_Utils.asString(_Utils.arrayAt(tArray, i))) return false;
if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i + 1)),
- _castToRti(_Utils.arrayAt(tArray, i + 1)))) return false;
+ _castToRti(_Utils.arrayAt(tArray, i + 1)), isLegacy)) return false;
}
return true;
}
// TODO(fishythefish): Support required named parameters.
-bool functionParametersEqual(
- _FunctionParameters sParameters, _FunctionParameters tParameters) =>
+bool functionParametersEqual(_FunctionParameters sParameters,
+ _FunctionParameters tParameters, isLegacy) =>
typesEqual(_FunctionParameters._getRequiredPositional(sParameters),
- _FunctionParameters._getRequiredPositional(tParameters)) &&
+ _FunctionParameters._getRequiredPositional(tParameters), isLegacy) &&
typesEqual(_FunctionParameters._getOptionalPositional(sParameters),
- _FunctionParameters._getOptionalPositional(tParameters)) &&
+ _FunctionParameters._getOptionalPositional(tParameters), isLegacy) &&
namedTypesEqual(_FunctionParameters._getOptionalNamed(sParameters),
- _FunctionParameters._getOptionalNamed(tParameters));
+ _FunctionParameters._getOptionalNamed(tParameters), isLegacy);
-// TODO(fishythefish): Update for NNBD - check for `Object?` instead of
-// `Object`.
-bool isTopType(Rti t) {
- if (isObjectType(t)) return true;
+bool isLegacyTopType(Rti t) => isTopType(t, true);
+bool isNnbdTopType(Rti t) => isTopType(t, false);
+bool isTopType(Rti t, bool isLegacy) {
+ if (isLegacy) {
+ if (isObjectType(t)) return true;
+ } else {
+ if (isNullableObjectType(t)) return true;
+ }
int kind = Rti._getKind(t);
return kind == Rti.kindDynamic ||
kind == Rti.kindVoid ||
kind == Rti.kindAny ||
kind == Rti.kindErased ||
- kind == Rti.kindFutureOr && isTopType(Rti._getFutureOrArgument(t));
+ kind == Rti.kindFutureOr &&
+ isTopType(Rti._getFutureOrArgument(t), isLegacy);
}
bool isObjectType(Rti t) => _Utils.isIdentical(t, TYPE_REF<Object>());
+// TODO(fishythefish): Use `TYPE_REF<Object?>()`.
+bool isNullableObjectType(Rti t) =>
+ Rti._getKind(t) == Rti.kindQuestion &&
+ isObjectType(Rti._getQuestionArgument(t));
bool isNullType(Rti t) => _Utils.isIdentical(t, TYPE_REF<Null>());
bool isFunctionType(Rti t) => _Utils.isIdentical(t, TYPE_REF<Function>());
bool isJsFunctionType(Rti t) =>
@@ -2808,8 +2875,8 @@
_Universe.addTypeParameterVariances(universe, variances);
}
-bool testingIsSubtype(universe, rti1, rti2) {
- return isSubtype(universe, _castToRti(rti1), _castToRti(rti2));
+bool testingIsLegacySubtype(universe, rti1, rti2) {
+ return isLegacySubtype(universe, _castToRti(rti1), _castToRti(rti2));
}
Object testingUniverseEval(universe, String recipe) {
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index 14b5e23..d86d322 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -91,10 +91,11 @@
categories: "Client,Server",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
- "js": const LibraryInfo("js/dart2js/js_dart2js.dart",
+ "js": const LibraryInfo("js/js.dart",
categories: "Client",
maturity: Maturity.STABLE,
- platforms: DART2JS_PLATFORM),
+ platforms: DART2JS_PLATFORM,
+ dart2jsPatchPath: "_internal/js_runtime/lib/js_patch.dart"),
"_js": const LibraryInfo("js/_js.dart",
categories: "Client",
dart2jsPatchPath: "js/_js_client.dart",
diff --git a/sdk/lib/js/js.dart b/sdk/lib/js/js.dart
new file mode 100644
index 0000000..139823d
--- /dev/null
+++ b/sdk/lib/js/js.dart
@@ -0,0 +1,235 @@
+// Copyright (c) 2013, 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.6
+
+/// Low-level support for interoperating with JavaScript.
+///
+/// You should usually use `package:js` instead of this library. For more
+/// information, see the [JS interop page](https://dart.dev/web/js-interop).
+///
+/// This library provides access to JavaScript objects from Dart, allowing
+/// Dart code to get and set properties, and call methods of JavaScript objects
+/// and invoke JavaScript functions. The library takes care of converting
+/// between Dart and JavaScript objects where possible, or providing proxies if
+/// conversion isn't possible.
+///
+/// This library does not make Dart objects usable from JavaScript, their
+/// methods and properties are not accessible, though it does allow Dart
+/// functions to be passed into and called from JavaScript.
+///
+/// [JsObject] is the core type and represents a proxy of a JavaScript object.
+/// JsObject gives access to the underlying JavaScript objects properties and
+/// methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
+/// created from proxies to JavaScript constructors.
+///
+/// The top-level getter [context] provides a [JsObject] that represents the
+/// global object in JavaScript, usually `window`.
+///
+/// The following example shows an alert dialog via a JavaScript call to the
+/// global function `alert()`:
+///
+/// import 'dart:js';
+///
+/// main() => context.callMethod('alert', ['Hello from Dart!']);
+///
+/// This example shows how to create a [JsObject] from a JavaScript constructor
+/// and access its properties:
+///
+/// import 'dart:js';
+///
+/// main() {
+/// var object = JsObject(context['Object']);
+/// object['greeting'] = 'Hello';
+/// object['greet'] = (name) => "${object['greeting']} $name";
+/// var message = object.callMethod('greet', ['JavaScript']);
+/// context['console'].callMethod('log', [message]);
+/// }
+///
+/// ## Proxying and automatic conversion
+///
+/// When setting properties on a JsObject or passing arguments to a Javascript
+/// method or function, Dart objects are automatically converted or proxied to
+/// JavaScript objects. When accessing JavaScript properties, or when a Dart
+/// closure is invoked from JavaScript, the JavaScript objects are also
+/// converted to Dart.
+///
+/// Functions and closures are proxied in such a way that they are callable. A
+/// Dart closure assigned to a JavaScript property is proxied by a function in
+/// JavaScript. A JavaScript function accessed from Dart is proxied by a
+/// [JsFunction], which has a [JsFunction.apply] method to invoke it.
+///
+/// The following types are transferred directly and not proxied:
+///
+/// * Basic types: `null`, `bool`, `num`, `String`, `DateTime`
+/// * `TypedData`, including its subclasses like `Int32List`, but _not_
+/// `ByteBuffer`
+/// * When compiling for the web, also: `Blob`, `Event`, `ImageData`,
+/// `KeyRange`, `Node`, and `Window`.
+///
+/// ## Converting collections with JsObject.jsify()
+///
+/// To create a JavaScript collection from a Dart collection use the
+/// [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
+/// into JavaScript Objects and Arrays.
+///
+/// The following expression creates a new JavaScript object with the properties
+/// `a` and `b` defined:
+///
+/// var jsMap = JsObject.jsify({'a': 1, 'b': 2});
+///
+/// This expression creates a JavaScript array:
+///
+/// var jsArray = JsObject.jsify([1, 2, 3]);
+///
+/// {@category Web}
+library dart.js;
+
+import 'dart:collection' show ListMixin;
+
+/// The JavaScript global object, usually `window`.
+external JsObject get context;
+
+/// A proxy on a JavaScript object.
+///
+/// The properties of the JavaScript object are accessible via the `[]` and
+/// `[]=` operators. Methods are callable via [callMethod].
+class JsObject {
+ /// Constructs a JavaScript object from its native [constructor] and returns
+ /// a proxy to it.
+ external factory JsObject(JsFunction constructor, [List arguments]);
+
+ /// Constructs a [JsObject] that proxies a native Dart object; _for expert use
+ /// only_.
+ ///
+ /// Use this constructor only if you wish to get access to JavaScript
+ /// properties attached to a browser host object, such as a Node or Blob, that
+ /// is normally automatically converted into a native Dart object.
+ ///
+ /// An exception will be thrown if [object] either is `null` or has the type
+ /// `bool`, `num`, or `String`.
+ external factory JsObject.fromBrowserObject(object);
+
+ /// Recursively converts a JSON-like collection of Dart objects to a
+ /// collection of JavaScript objects and returns a [JsObject] proxy to it.
+ ///
+ /// [object] must be a [Map] or [Iterable], the contents of which are also
+ /// converted. Maps and Iterables are copied to a new JavaScript object.
+ /// Primitives and other transferable values are directly converted to their
+ /// JavaScript type, and all other objects are proxied.
+ external factory JsObject.jsify(object);
+
+ /// Returns the value associated with [property] from the proxied JavaScript
+ /// object.
+ ///
+ /// The type of [property] must be either [String] or [num].
+ external dynamic operator [](property);
+
+ // Sets the value associated with [property] on the proxied JavaScript
+ // object.
+ //
+ // The type of [property] must be either [String] or [num].
+ external void operator []=(property, value);
+
+ int get hashCode => 0;
+
+ external bool operator ==(other);
+
+ /// Returns `true` if the JavaScript object contains the specified property
+ /// either directly or though its prototype chain.
+ ///
+ /// This is the equivalent of the `in` operator in JavaScript.
+ external bool hasProperty(property);
+
+ /// Removes [property] from the JavaScript object.
+ ///
+ /// This is the equivalent of the `delete` operator in JavaScript.
+ external void deleteProperty(property);
+
+ /// Returns `true` if the JavaScript object has [type] in its prototype chain.
+ ///
+ /// This is the equivalent of the `instanceof` operator in JavaScript.
+ external bool instanceof(JsFunction type);
+
+ /// Returns the result of the JavaScript objects `toString` method.
+ external String toString();
+
+ /// Calls [method] on the JavaScript object with the arguments [args] and
+ /// returns the result.
+ ///
+ /// The type of [method] must be either [String] or [num].
+ external dynamic callMethod(method, [List args]);
+}
+
+/// A proxy on a JavaScript Function object.
+class JsFunction extends JsObject {
+ /// Returns a [JsFunction] that captures its 'this' binding and calls [f]
+ /// with the value of JavaScript `this` passed as the first argument.
+ external factory JsFunction.withThis(Function f);
+
+ /// Invokes the JavaScript function with arguments [args]. If [thisArg] is
+ /// supplied it is the value of `this` for the invocation.
+ external dynamic apply(List args, {thisArg});
+}
+
+/// A [List] that proxies a JavaScript array.
+class JsArray<E> extends JsObject with ListMixin<E> {
+ /// Creates an empty JavaScript array.
+ external factory JsArray();
+
+ /// Creates a new JavaScript array and initializes it to the contents of
+ /// [other].
+ external factory JsArray.from(Iterable<E> other);
+
+ // Methods required by ListMixin
+
+ external E operator [](dynamic index);
+
+ external void operator []=(dynamic index, E value);
+
+ external int get length;
+
+ external void set length(int length);
+
+ // Methods overridden for better performance
+
+ external void add(E value);
+
+ external void addAll(Iterable<E> iterable);
+
+ external void insert(int index, E element);
+
+ external E removeAt(int index);
+
+ external E removeLast();
+
+ external void removeRange(int start, int end);
+
+ external void setRange(int start, int end, Iterable<E> iterable,
+ [int skipCount = 0]);
+
+ external void sort([int compare(E a, E b)]);
+}
+
+/// Returns a wrapper around function [f] that can be called from JavaScript
+/// using `package:js` JavaScript interop.
+///
+/// The calling conventions in Dart2Js differ from JavaScript and so, by
+/// default, it is not possible to call a Dart function directly. Wrapping with
+/// `allowInterop` creates a function that can be called from JavaScript or
+/// Dart. The semantics of the wrapped function are still more strict than
+/// JavaScript, and the function will throw if called with too many or too few
+/// arguments.
+///
+/// Calling this method repeatedly on a function will return the same result.
+external F allowInterop<F extends Function>(F f);
+
+/// Returns a wrapper around function [f] that can be called from JavaScript
+/// using `package:js` JavaScript interop, passing JavaScript `this` as the first
+/// argument.
+///
+/// See [allowInterop].
+///
+/// When called from Dart, [null] will be passed as the first argument.
+external Function allowInteropCaptureThis(Function f);
diff --git a/sdk/lib/js/js_sources.gni b/sdk/lib/js/js_sources.gni
index 91f6d0c..67d1660 100644
--- a/sdk/lib/js/js_sources.gni
+++ b/sdk/lib/js/js_sources.gni
@@ -2,4 +2,4 @@
# 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.
-js_sdk_sources = [ "dart2js/js_dart2js.dart" ]
+js_sdk_sources = [ "js.dart", "dart2js/js_dart2js.dart" ]
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index 4335766..f31091f 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -1,18 +1,46 @@
{
"comment:0": "NOTE: THIS FILE IS GENERATED. DO NOT EDIT.",
"comment:1": "Instead modify 'sdk/lib/libraries.yaml' and follow the instructions therein.",
+ "none": {
+ "libraries": {}
+ },
"vm": {
"libraries": {
"_builtin": {
"uri": "_internal/vm/bin/builtin.dart"
},
- "cli": {
+ "_internal": {
+ "uri": "internal/internal.dart",
"patches": [
- "_internal/vm/bin/cli_patch.dart"
- ],
- "uri": "cli/cli.dart"
+ "_internal/vm/lib/internal_patch.dart",
+ "_internal/vm/lib/class_id_fasta.dart",
+ "_internal/vm/lib/print_patch.dart",
+ "_internal/vm/lib/symbol_patch.dart",
+ "internal/patch.dart"
+ ]
+ },
+ "async": {
+ "uri": "async/async.dart",
+ "patches": [
+ "_internal/vm/lib/async_patch.dart",
+ "_internal/vm/lib/deferred_load_patch.dart",
+ "_internal/vm/lib/schedule_microtask_patch.dart",
+ "_internal/vm/lib/timer_patch.dart"
+ ]
+ },
+ "collection": {
+ "uri": "collection/collection.dart",
+ "patches": [
+ "_internal/vm/lib/collection_patch.dart",
+ "_internal/vm/lib/compact_hash.dart"
+ ]
+ },
+ "convert": {
+ "uri": "convert/convert.dart",
+ "patches": "_internal/vm/lib/convert_patch.dart"
},
"core": {
+ "uri": "core/core.dart",
"patches": [
"_internal/vm/lib/core_patch.dart",
"_internal/vm/lib/array.dart",
@@ -44,73 +72,35 @@
"_internal/vm/lib/type_patch.dart",
"_internal/vm/lib/uri_patch.dart",
"_internal/vm/lib/weak_property.dart"
- ],
- "uri": "core/core.dart"
- },
- "async": {
- "patches": [
- "_internal/vm/lib/async_patch.dart",
- "_internal/vm/lib/deferred_load_patch.dart",
- "_internal/vm/lib/schedule_microtask_patch.dart",
- "_internal/vm/lib/timer_patch.dart"
- ],
- "uri": "async/async.dart"
- },
- "collection": {
- "patches": [
- "_internal/vm/lib/collection_patch.dart",
- "_internal/vm/lib/compact_hash.dart"
- ],
- "uri": "collection/collection.dart"
- },
- "ffi": {
- "patches": [
- "_internal/vm/lib/ffi_patch.dart",
- "_internal/vm/lib/ffi_dynamic_library_patch.dart",
- "_internal/vm/lib/ffi_native_type_patch.dart"
- ],
- "uri": "ffi/ffi.dart"
- },
- "typed_data": {
- "patches": "_internal/vm/lib/typed_data_patch.dart",
- "uri": "typed_data/typed_data.dart"
- },
- "nativewrappers": {
- "uri": "html/dartium/nativewrappers.dart"
- },
- "mirrors": {
- "patches": [
- "_internal/vm/lib/mirrors_patch.dart",
- "_internal/vm/lib/mirrors_impl.dart",
- "_internal/vm/lib/mirror_reference.dart"
- ],
- "uri": "mirrors/mirrors.dart"
+ ]
},
"developer": {
+ "uri": "developer/developer.dart",
"patches": [
"_internal/vm/lib/developer.dart",
"_internal/vm/lib/profiler.dart",
"_internal/vm/lib/timeline.dart"
- ],
- "uri": "developer/developer.dart"
+ ]
},
- "isolate": {
+ "ffi": {
+ "uri": "ffi/ffi.dart",
"patches": [
- "_internal/vm/lib/isolate_patch.dart",
- "_internal/vm/lib/timer_impl.dart"
- ],
- "uri": "isolate/isolate.dart"
- },
- "_vmservice": {
- "uri": "vmservice/vmservice.dart"
+ "_internal/vm/lib/ffi_patch.dart",
+ "_internal/vm/lib/ffi_dynamic_library_patch.dart",
+ "_internal/vm/lib/ffi_native_type_patch.dart"
+ ]
},
"wasm": {
+ "uri": "wasm/wasm.dart",
"patches": [
"_internal/vm/lib/wasm_patch.dart"
- ],
- "uri": "wasm/wasm.dart"
+ ]
+ },
+ "_http": {
+ "uri": "_http/http.dart"
},
"io": {
+ "uri": "io/io.dart",
"patches": [
"_internal/vm/bin/common_patch.dart",
"_internal/vm/bin/directory_patch.dart",
@@ -126,358 +116,371 @@
"_internal/vm/bin/stdio_patch.dart",
"_internal/vm/bin/secure_socket_patch.dart",
"_internal/vm/bin/sync_socket_patch.dart"
- ],
- "uri": "io/io.dart"
+ ]
},
- "_internal": {
+ "isolate": {
+ "uri": "isolate/isolate.dart",
"patches": [
- "_internal/vm/lib/internal_patch.dart",
- "_internal/vm/lib/class_id_fasta.dart",
- "_internal/vm/lib/print_patch.dart",
- "_internal/vm/lib/symbol_patch.dart",
- "internal/patch.dart"
- ],
- "uri": "internal/internal.dart"
- },
- "convert": {
- "patches": "_internal/vm/lib/convert_patch.dart",
- "uri": "convert/convert.dart"
+ "_internal/vm/lib/isolate_patch.dart",
+ "_internal/vm/lib/timer_impl.dart"
+ ]
},
"math": {
- "patches": "_internal/vm/lib/math_patch.dart",
- "uri": "math/math.dart"
+ "uri": "math/math.dart",
+ "patches": "_internal/vm/lib/math_patch.dart"
},
- "_http": {
- "uri": "_http/http.dart"
+ "mirrors": {
+ "uri": "mirrors/mirrors.dart",
+ "patches": [
+ "_internal/vm/lib/mirrors_patch.dart",
+ "_internal/vm/lib/mirrors_impl.dart",
+ "_internal/vm/lib/mirror_reference.dart"
+ ]
+ },
+ "nativewrappers": {
+ "uri": "html/dartium/nativewrappers.dart"
+ },
+ "cli": {
+ "uri": "cli/cli.dart",
+ "patches": [
+ "_internal/vm/bin/cli_patch.dart"
+ ]
+ },
+ "typed_data": {
+ "uri": "typed_data/typed_data.dart",
+ "patches": "_internal/vm/lib/typed_data_patch.dart"
+ },
+ "_vmservice": {
+ "uri": "vmservice/vmservice.dart"
},
"vmservice_io": {
"uri": "../../runtime/bin/vmservice/vmservice_io.dart"
}
}
},
- "none": {
- "libraries": {}
- },
"dart2js": {
"libraries": {
"async": {
- "patches": "_internal/js_runtime/lib/async_patch.dart",
- "uri": "async/async.dart"
+ "uri": "async/async.dart",
+ "patches": "_internal/js_runtime/lib/async_patch.dart"
},
- "_interceptors": {
- "uri": "_internal/js_runtime/lib/interceptors.dart"
+ "collection": {
+ "uri": "collection/collection.dart",
+ "patches": "_internal/js_runtime/lib/collection_patch.dart"
},
- "mirrors": {
- "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
- "supported": false,
- "uri": "mirrors/mirrors.dart"
+ "convert": {
+ "uri": "convert/convert.dart",
+ "patches": "_internal/js_runtime/lib/convert_patch.dart"
},
- "_js_embedded_names": {
- "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+ "core": {
+ "uri": "core/core.dart",
+ "patches": "_internal/js_runtime/lib/core_patch.dart"
},
- "io": {
- "patches": "_internal/js_runtime/lib/io_patch.dart",
- "supported": false,
- "uri": "io/io.dart"
+ "developer": {
+ "uri": "developer/developer.dart",
+ "patches": "_internal/js_runtime/lib/developer_patch.dart"
},
- "_internal": {
- "patches": "_internal/js_runtime/lib/internal_patch.dart",
- "uri": "internal/internal.dart"
- },
- "_metadata": {
- "uri": "html/html_common/metadata.dart"
- },
- "_async_await_error_codes": {
- "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
- },
- "_http": {
- "uri": "_http/http.dart"
- },
- "_js_primitives": {
- "uri": "_internal/js_runtime/lib/js_primitives.dart"
- },
- "_js_helper": {
- "uri": "_internal/js_runtime/lib/js_helper.dart"
- },
- "js": {
- "uri": "js/dart2js/js_dart2js.dart"
+ "html": {
+ "uri": "html/dart2js/html_dart2js.dart"
},
"html_common": {
"uri": "html/html_common/html_common_dart2js.dart"
},
- "_recipe_syntax": {
- "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+ "indexed_db": {
+ "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
},
- "_native_typed_data": {
- "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+ "_http": {
+ "uri": "_http/http.dart"
},
- "_js_names": {
- "uri": "_internal/js_runtime/lib/js_names.dart"
+ "io": {
+ "uri": "io/io.dart",
+ "patches": "_internal/js_runtime/lib/io_patch.dart",
+ "supported": false
},
- "core": {
- "patches": "_internal/js_runtime/lib/core_patch.dart",
- "uri": "core/core.dart"
+ "isolate": {
+ "uri": "isolate/isolate.dart",
+ "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+ "supported": false
},
- "collection": {
- "patches": "_internal/js_runtime/lib/collection_patch.dart",
- "uri": "collection/collection.dart"
+ "js": {
+ "uri": "js/js.dart",
+ "patches": "_internal/js_runtime/lib/js_patch.dart"
+ },
+ "_js": {
+ "uri": "js/_js.dart",
+ "patches": "js/_js_client.dart"
},
"js_util": {
"uri": "js_util/dart2js/js_util_dart2js.dart"
},
+ "math": {
+ "uri": "math/math.dart",
+ "patches": "_internal/js_runtime/lib/math_patch.dart"
+ },
+ "mirrors": {
+ "uri": "mirrors/mirrors.dart",
+ "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+ "supported": false
+ },
"typed_data": {
- "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
- "uri": "typed_data/typed_data.dart"
+ "uri": "typed_data/typed_data.dart",
+ "patches": "_internal/js_runtime/lib/typed_data_patch.dart"
+ },
+ "_native_typed_data": {
+ "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+ },
+ "svg": {
+ "uri": "svg/dart2js/svg_dart2js.dart"
},
"web_audio": {
"uri": "web_audio/dart2js/web_audio_dart2js.dart"
},
- "html": {
- "uri": "html/dart2js/html_dart2js.dart"
- },
- "isolate": {
- "patches": "_internal/js_runtime/lib/isolate_patch.dart",
- "supported": false,
- "uri": "isolate/isolate.dart"
- },
- "developer": {
- "patches": "_internal/js_runtime/lib/developer_patch.dart",
- "uri": "developer/developer.dart"
- },
"web_gl": {
"uri": "web_gl/dart2js/web_gl_dart2js.dart"
},
- "indexed_db": {
- "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
- },
- "_js": {
- "patches": "js/_js_client.dart",
- "uri": "js/_js.dart"
- },
- "convert": {
- "patches": "_internal/js_runtime/lib/convert_patch.dart",
- "uri": "convert/convert.dart"
- },
- "math": {
- "patches": "_internal/js_runtime/lib/math_patch.dart",
- "uri": "math/math.dart"
- },
- "_foreign_helper": {
- "uri": "_internal/js_runtime/lib/foreign_helper.dart"
- },
"web_sql": {
"uri": "web_sql/dart2js/web_sql_dart2js.dart"
},
+ "_internal": {
+ "uri": "internal/internal.dart",
+ "patches": "_internal/js_runtime/lib/internal_patch.dart"
+ },
+ "_js_helper": {
+ "uri": "_internal/js_runtime/lib/js_helper.dart"
+ },
"_rti": {
"uri": "_internal/js_runtime/lib/rti.dart"
},
- "svg": {
- "uri": "svg/dart2js/svg_dart2js.dart"
- }
- }
- },
- "dartdevc": {
- "libraries": {
- "async": {
- "patches": "_internal/js_dev_runtime/patch/async_patch.dart",
- "uri": "async/async.dart"
- },
- "_runtime": {
- "uri": "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
- },
"_interceptors": {
- "uri": "_internal/js_dev_runtime/private/interceptors.dart"
+ "uri": "_internal/js_runtime/lib/interceptors.dart"
},
- "mirrors": {
- "patches": "_internal/js_dev_runtime/patch/mirrors_patch.dart",
- "supported": false,
- "uri": "mirrors/mirrors.dart"
+ "_foreign_helper": {
+ "uri": "_internal/js_runtime/lib/foreign_helper.dart"
},
- "_debugger": {
- "uri": "_internal/js_dev_runtime/private/debugger.dart"
+ "_js_names": {
+ "uri": "_internal/js_runtime/lib/js_names.dart"
},
- "io": {
- "patches": "_internal/js_dev_runtime/patch/io_patch.dart",
- "supported": false,
- "uri": "io/io.dart"
+ "_js_primitives": {
+ "uri": "_internal/js_runtime/lib/js_primitives.dart"
},
- "_internal": {
- "patches": "_internal/js_dev_runtime/patch/internal_patch.dart",
- "uri": "internal/internal.dart"
+ "_js_embedded_names": {
+ "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+ },
+ "_async_await_error_codes": {
+ "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+ },
+ "_recipe_syntax": {
+ "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
},
"_metadata": {
"uri": "html/html_common/metadata.dart"
- },
- "_http": {
- "uri": "_http/http.dart"
- },
- "_js_primitives": {
- "uri": "_internal/js_dev_runtime/private/js_primitives.dart"
- },
- "_js_helper": {
- "uri": "_internal/js_dev_runtime/private/js_helper.dart"
- },
- "js": {
- "uri": "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
- },
- "_js_mirrors": {
- "uri": "_internal/js_dev_runtime/private/js_mirrors.dart"
- },
- "html_common": {
- "uri": "html/html_common/html_common_dart2js.dart"
- },
- "_native_typed_data": {
- "uri": "_internal/js_dev_runtime/private/native_typed_data.dart"
- },
- "core": {
- "patches": "_internal/js_dev_runtime/patch/core_patch.dart",
- "uri": "core/core.dart"
- },
- "js_util": {
- "uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
- },
- "collection": {
- "patches": "_internal/js_dev_runtime/patch/collection_patch.dart",
- "uri": "collection/collection.dart"
- },
- "typed_data": {
- "patches": "_internal/js_dev_runtime/patch/typed_data_patch.dart",
- "uri": "typed_data/typed_data.dart"
- },
- "web_audio": {
- "uri": "web_audio/dart2js/web_audio_dart2js.dart"
- },
- "html": {
- "uri": "html/dart2js/html_dart2js.dart"
- },
- "developer": {
- "patches": "_internal/js_dev_runtime/patch/developer_patch.dart",
- "uri": "developer/developer.dart"
- },
- "isolate": {
- "patches": "_internal/js_dev_runtime/patch/isolate_patch.dart",
- "supported": false,
- "uri": "isolate/isolate.dart"
- },
- "web_gl": {
- "uri": "web_gl/dart2js/web_gl_dart2js.dart"
- },
- "indexed_db": {
- "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
- },
- "convert": {
- "patches": "_internal/js_dev_runtime/patch/convert_patch.dart",
- "uri": "convert/convert.dart"
- },
- "_isolate_helper": {
- "uri": "_internal/js_dev_runtime/private/isolate_helper.dart"
- },
- "math": {
- "patches": "_internal/js_dev_runtime/patch/math_patch.dart",
- "uri": "math/math.dart"
- },
- "_foreign_helper": {
- "uri": "_internal/js_dev_runtime/private/foreign_helper.dart"
- },
- "web_sql": {
- "uri": "web_sql/dart2js/web_sql_dart2js.dart"
- },
- "svg": {
- "uri": "svg/dart2js/svg_dart2js.dart"
}
}
},
"dart2js_server": {
"libraries": {
"async": {
- "patches": "_internal/js_runtime/lib/async_patch.dart",
- "uri": "async/async.dart"
+ "uri": "async/async.dart",
+ "patches": "_internal/js_runtime/lib/async_patch.dart"
},
- "mirrors": {
- "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
- "supported": false,
- "uri": "mirrors/mirrors.dart"
+ "collection": {
+ "uri": "collection/collection.dart",
+ "patches": "_internal/js_runtime/lib/collection_patch.dart"
},
- "_interceptors": {
- "uri": "_internal/js_runtime/lib/interceptors.dart"
+ "convert": {
+ "uri": "convert/convert.dart",
+ "patches": "_internal/js_runtime/lib/convert_patch.dart"
},
- "_js_embedded_names": {
- "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+ "core": {
+ "uri": "core/core.dart",
+ "patches": "_internal/js_runtime/lib/core_patch.dart"
},
- "io": {
- "patches": "_internal/js_runtime/lib/io_patch.dart",
- "supported": false,
- "uri": "io/io.dart"
- },
- "_internal": {
- "patches": "_internal/js_runtime/lib/internal_patch.dart",
- "uri": "internal/internal.dart"
- },
- "_async_await_error_codes": {
- "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+ "developer": {
+ "uri": "developer/developer.dart",
+ "patches": "_internal/js_runtime/lib/developer_patch.dart"
},
"_http": {
"uri": "_http/http.dart"
},
- "_js_helper": {
- "uri": "_internal/js_runtime/lib/js_helper.dart"
+ "io": {
+ "uri": "io/io.dart",
+ "patches": "_internal/js_runtime/lib/io_patch.dart",
+ "supported": false
},
- "_js_primitives": {
- "uri": "_internal/js_runtime/lib/js_primitives.dart"
+ "isolate": {
+ "uri": "isolate/isolate.dart",
+ "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+ "supported": false
},
"js": {
- "uri": "js/dart2js/js_dart2js.dart"
+ "uri": "js/js.dart",
+ "patches": "_internal/js_runtime/lib/js_patch.dart"
},
- "_recipe_syntax": {
- "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
- },
- "_native_typed_data": {
- "uri": "_internal/js_runtime/lib/native_typed_data.dart"
- },
- "core": {
- "patches": "_internal/js_runtime/lib/core_patch.dart",
- "uri": "core/core.dart"
- },
- "_js_names": {
- "uri": "_internal/js_runtime/lib/js_names.dart"
+ "_js": {
+ "uri": "js/_js.dart",
+ "patches": "js/_js_server.dart"
},
"js_util": {
"uri": "js_util/dart2js/js_util_dart2js.dart"
},
- "collection": {
- "patches": "_internal/js_runtime/lib/collection_patch.dart",
- "uri": "collection/collection.dart"
+ "math": {
+ "uri": "math/math.dart",
+ "patches": "_internal/js_runtime/lib/math_patch.dart"
+ },
+ "mirrors": {
+ "uri": "mirrors/mirrors.dart",
+ "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+ "supported": false
},
"typed_data": {
- "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
- "uri": "typed_data/typed_data.dart"
+ "uri": "typed_data/typed_data.dart",
+ "patches": "_internal/js_runtime/lib/typed_data_patch.dart"
},
- "isolate": {
- "patches": "_internal/js_runtime/lib/isolate_patch.dart",
- "supported": false,
- "uri": "isolate/isolate.dart"
+ "_native_typed_data": {
+ "uri": "_internal/js_runtime/lib/native_typed_data.dart"
},
- "developer": {
- "patches": "_internal/js_runtime/lib/developer_patch.dart",
- "uri": "developer/developer.dart"
+ "_internal": {
+ "uri": "internal/internal.dart",
+ "patches": "_internal/js_runtime/lib/internal_patch.dart"
},
- "_js": {
- "patches": "js/_js_server.dart",
- "uri": "js/_js.dart"
+ "_js_helper": {
+ "uri": "_internal/js_runtime/lib/js_helper.dart"
},
- "convert": {
- "patches": "_internal/js_runtime/lib/convert_patch.dart",
- "uri": "convert/convert.dart"
+ "_rti": {
+ "uri": "_internal/js_runtime/lib/rti.dart"
},
- "math": {
- "patches": "_internal/js_runtime/lib/math_patch.dart",
- "uri": "math/math.dart"
+ "_interceptors": {
+ "uri": "_internal/js_runtime/lib/interceptors.dart"
},
"_foreign_helper": {
"uri": "_internal/js_runtime/lib/foreign_helper.dart"
},
- "_rti": {
- "uri": "_internal/js_runtime/lib/rti.dart"
+ "_js_names": {
+ "uri": "_internal/js_runtime/lib/js_names.dart"
+ },
+ "_js_primitives": {
+ "uri": "_internal/js_runtime/lib/js_primitives.dart"
+ },
+ "_js_embedded_names": {
+ "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+ },
+ "_async_await_error_codes": {
+ "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+ },
+ "_recipe_syntax": {
+ "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+ }
+ }
+ },
+ "dartdevc": {
+ "libraries": {
+ "_runtime": {
+ "uri": "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
+ },
+ "_debugger": {
+ "uri": "_internal/js_dev_runtime/private/debugger.dart"
+ },
+ "_foreign_helper": {
+ "uri": "_internal/js_dev_runtime/private/foreign_helper.dart"
+ },
+ "_http": {
+ "uri": "_http/http.dart"
+ },
+ "_interceptors": {
+ "uri": "_internal/js_dev_runtime/private/interceptors.dart"
+ },
+ "_internal": {
+ "uri": "internal/internal.dart",
+ "patches": "_internal/js_dev_runtime/patch/internal_patch.dart"
+ },
+ "_isolate_helper": {
+ "uri": "_internal/js_dev_runtime/private/isolate_helper.dart"
+ },
+ "_js_helper": {
+ "uri": "_internal/js_dev_runtime/private/js_helper.dart"
+ },
+ "_js_mirrors": {
+ "uri": "_internal/js_dev_runtime/private/js_mirrors.dart"
+ },
+ "_js_primitives": {
+ "uri": "_internal/js_dev_runtime/private/js_primitives.dart"
+ },
+ "_metadata": {
+ "uri": "html/html_common/metadata.dart"
+ },
+ "_native_typed_data": {
+ "uri": "_internal/js_dev_runtime/private/native_typed_data.dart"
+ },
+ "async": {
+ "uri": "async/async.dart",
+ "patches": "_internal/js_dev_runtime/patch/async_patch.dart"
+ },
+ "collection": {
+ "uri": "collection/collection.dart",
+ "patches": "_internal/js_dev_runtime/patch/collection_patch.dart"
+ },
+ "convert": {
+ "uri": "convert/convert.dart",
+ "patches": "_internal/js_dev_runtime/patch/convert_patch.dart"
+ },
+ "core": {
+ "uri": "core/core.dart",
+ "patches": "_internal/js_dev_runtime/patch/core_patch.dart"
+ },
+ "developer": {
+ "uri": "developer/developer.dart",
+ "patches": "_internal/js_dev_runtime/patch/developer_patch.dart"
+ },
+ "io": {
+ "uri": "io/io.dart",
+ "patches": "_internal/js_dev_runtime/patch/io_patch.dart",
+ "supported": false
+ },
+ "isolate": {
+ "uri": "isolate/isolate.dart",
+ "patches": "_internal/js_dev_runtime/patch/isolate_patch.dart",
+ "supported": false
+ },
+ "mirrors": {
+ "uri": "mirrors/mirrors.dart",
+ "patches": "_internal/js_dev_runtime/patch/mirrors_patch.dart",
+ "supported": false
+ },
+ "math": {
+ "uri": "math/math.dart",
+ "patches": "_internal/js_dev_runtime/patch/math_patch.dart"
+ },
+ "typed_data": {
+ "uri": "typed_data/typed_data.dart",
+ "patches": "_internal/js_dev_runtime/patch/typed_data_patch.dart"
+ },
+ "html": {
+ "uri": "html/dart2js/html_dart2js.dart"
+ },
+ "html_common": {
+ "uri": "html/html_common/html_common_dart2js.dart"
+ },
+ "indexed_db": {
+ "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
+ },
+ "js": {
+ "uri": "js/js.dart",
+ "patches": "_internal/js_dev_runtime/patch/js_patch.dart"
+ },
+ "js_util": {
+ "uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+ },
+ "svg": {
+ "uri": "svg/dart2js/svg_dart2js.dart"
+ },
+ "web_audio": {
+ "uri": "web_audio/dart2js/web_audio_dart2js.dart"
+ },
+ "web_gl": {
+ "uri": "web_gl/dart2js/web_gl_dart2js.dart"
+ },
+ "web_sql": {
+ "uri": "web_sql/dart2js/web_sql_dart2js.dart"
}
}
}
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index 78fa02d..d4a3d8b 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -200,7 +200,8 @@
supported: false
js:
- uri: "js/dart2js/js_dart2js.dart"
+ uri: "js/js.dart"
+ patches: "_internal/js_runtime/lib/js_patch.dart"
_js:
uri: "js/_js.dart"
@@ -307,7 +308,8 @@
supported: false
js:
- uri: "js/dart2js/js_dart2js.dart"
+ uri: "js/js.dart"
+ patches: "_internal/js_runtime/lib/js_patch.dart"
_js:
uri: "js/_js.dart"
@@ -455,7 +457,8 @@
uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
js:
- uri: "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+ uri: "js/js.dart"
+ patches: "_internal/js_dev_runtime/patch/js_patch.dart"
js_util:
uri: "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
diff --git a/sdk_nnbd/lib/_http/http_impl.dart b/sdk_nnbd/lib/_http/http_impl.dart
index a119a93..c18d12d 100644
--- a/sdk_nnbd/lib/_http/http_impl.dart
+++ b/sdk_nnbd/lib/_http/http_impl.dart
@@ -961,7 +961,7 @@
}
String _findReasonPhrase(int statusCode) {
- var resonPhrase = _reasonPhrase;
+ var reasonPhrase = _reasonPhrase;
if (reasonPhrase != null) {
return reasonPhrase;
}
diff --git a/sdk_nnbd/lib/_http/http_parser.dart b/sdk_nnbd/lib/_http/http_parser.dart
index a3ae3c2f..1561ce8 100644
--- a/sdk_nnbd/lib/_http/http_parser.dart
+++ b/sdk_nnbd/lib/_http/http_parser.dart
@@ -975,7 +975,7 @@
return true;
}
- int _expect(int val1, int val2) {
+ void _expect(int val1, int val2) {
if (val1 != val2) {
throw new HttpException("Failed to parse HTTP");
}
diff --git a/sdk_nnbd/lib/_http/websocket.dart b/sdk_nnbd/lib/_http/websocket.dart
index 6dd55b2..9c670a6 100644
--- a/sdk_nnbd/lib/_http/websocket.dart
+++ b/sdk_nnbd/lib/_http/websocket.dart
@@ -445,7 +445,7 @@
/**
* Closes the WebSocket connection. Set the optional [code] and [reason]
* arguments to send close information to the remote peer. If they are
- * omitted, the peer will see [WebSocketStatus.NO_STATUS_RECEIVED] code
+ * omitted, the peer will see [WebSocketStatus.noStatusReceived] code
* with no reason.
*/
Future close([int? code, String? reason]);
diff --git a/sdk_nnbd/lib/_http/websocket_impl.dart b/sdk_nnbd/lib/_http/websocket_impl.dart
index af7c1bb..22befce 100644
--- a/sdk_nnbd/lib/_http/websocket_impl.dart
+++ b/sdk_nnbd/lib/_http/websocket_impl.dart
@@ -347,14 +347,14 @@
void _controlFrameEnd() {
switch (_opcode) {
case _WebSocketOpcode.CLOSE:
- closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
+ closeCode = WebSocketStatus.noStatusReceived;
var payload = _payload.takeBytes();
if (payload.length > 0) {
if (payload.length == 1) {
throw new WebSocketException("Protocol error");
}
closeCode = payload[0] << 8 | payload[1];
- if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) {
+ if (closeCode == WebSocketStatus.noStatusReceived) {
throw new WebSocketException("Protocol error");
}
if (payload.length > 2) {
@@ -1138,9 +1138,9 @@
}, onError: (Object error, StackTrace? stackTrace) {
_closeTimer?.cancel();
if (error is FormatException) {
- _close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA);
+ _close(WebSocketStatus.invalidFramePayloadData);
} else {
- _close(WebSocketStatus.PROTOCOL_ERROR);
+ _close(WebSocketStatus.protocolError);
}
// An error happened, set the close code set above.
_closeCode = _outCloseCode;
@@ -1195,7 +1195,7 @@
_consumer.add(new _WebSocketPing());
_pingTimer = new Timer(interval, () {
// No pong received.
- _close(WebSocketStatus.GOING_AWAY);
+ _close(WebSocketStatus.goingAway);
});
});
}
@@ -1300,12 +1300,12 @@
static bool _isReservedStatusCode(int? code) {
return code != null &&
- (code < WebSocketStatus.NORMAL_CLOSURE ||
- code == WebSocketStatus.RESERVED_1004 ||
- code == WebSocketStatus.NO_STATUS_RECEIVED ||
- code == WebSocketStatus.ABNORMAL_CLOSURE ||
- (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
- code < WebSocketStatus.RESERVED_1015) ||
- (code >= WebSocketStatus.RESERVED_1015 && code < 3000));
+ (code < WebSocketStatus.normalClosure ||
+ code == WebSocketStatus.reserved1004 ||
+ code == WebSocketStatus.noStatusReceived ||
+ code == WebSocketStatus.abnormalClosure ||
+ (code > WebSocketStatus.internalServerError &&
+ code < WebSocketStatus.reserved1015) ||
+ (code >= WebSocketStatus.reserved1015 && code < 3000));
}
}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
deleted file mode 100644
index 01eed1e..0000000
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
+++ /dev/null
@@ -1,568 +0,0 @@
-// Copyright (c) 2015, 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
-
-// DDC version of sdk/lib/js/dart2js/js_dart2js.dart
-
-/// Low-level support for interoperating with JavaScript.
-///
-/// You should usually use `package:js` instead of this library. For more
-/// information, see the [JS interop page](https://dart.dev/web/js-interop).
-///
-/// This library provides access to JavaScript objects from Dart, allowing
-/// Dart code to get and set properties, and call methods of JavaScript objects
-/// and invoke JavaScript functions. The library takes care of converting
-/// between Dart and JavaScript objects where possible, or providing proxies if
-/// conversion isn't possible.
-///
-/// This library does not make Dart objects usable from JavaScript, their
-/// methods and properties are not accessible, though it does allow Dart
-/// functions to be passed into and called from JavaScript.
-///
-/// [JsObject] is the core type and represents a proxy of a JavaScript object.
-/// JsObject gives access to the underlying JavaScript objects properties and
-/// methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
-/// created from proxies to JavaScript constructors.
-///
-/// The top-level getter [context] provides a [JsObject] that represents the
-/// global object in JavaScript, usually `window`.
-///
-/// The following example shows an alert dialog via a JavaScript call to the
-/// global function `alert()`:
-///
-/// import 'dart:js';
-///
-/// main() => context.callMethod('alert', ['Hello from Dart!']);
-///
-/// This example shows how to create a [JsObject] from a JavaScript constructor
-/// and access its properties:
-///
-/// import 'dart:js';
-///
-/// main() {
-/// var object = JsObject(context['Object']);
-/// object['greeting'] = 'Hello';
-/// object['greet'] = (name) => "${object['greeting']} $name";
-/// var message = object.callMethod('greet', ['JavaScript']);
-/// context['console'].callMethod('log', [message]);
-/// }
-///
-/// ## Proxying and automatic conversion
-///
-/// When setting properties on a JsObject or passing arguments to a Javascript
-/// method or function, Dart objects are automatically converted or proxied to
-/// JavaScript objects. When accessing JavaScript properties, or when a Dart
-/// closure is invoked from JavaScript, the JavaScript objects are also
-/// converted to Dart.
-///
-/// Functions and closures are proxied in such a way that they are callable. A
-/// Dart closure assigned to a JavaScript property is proxied by a function in
-/// JavaScript. A JavaScript function accessed from Dart is proxied by a
-/// [JsFunction], which has a [apply] method to invoke it.
-///
-/// The following types are transferred directly and not proxied:
-///
-/// * Basic types: `null`, `bool`, `num`, `String`, `DateTime`
-/// * `TypedData`, including its subclasses like `Int32List`, but _not_
-/// `ByteBuffer`
-/// * When compiling for the web, also: `Blob`, `Event`, `ImageData`,
-/// `KeyRange`, `Node`, and `Window`.
-///
-/// ## Converting collections with JsObject.jsify()
-///
-/// To create a JavaScript collection from a Dart collection use the
-/// [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
-/// into JavaScript Objects and Arrays.
-///
-/// The following expression creates a new JavaScript object with the properties
-/// `a` and `b` defined:
-///
-/// var jsMap = JsObject.jsify({'a': 1, 'b': 2});
-///
-/// This expression creates a JavaScript array:
-///
-/// var jsArray = JsObject.jsify([1, 2, 3]);
-///
-/// {@category Web}
-library dart.js;
-
-import 'dart:collection' show HashMap, ListMixin;
-
-import 'dart:_js_helper' show Primitives;
-import 'dart:_foreign_helper' show JS;
-import 'dart:_runtime' as dart;
-
-/// The JavaScript global object, usually `window`.
-final JsObject context = _wrapToDart(dart.global_);
-
-/// A proxy on a JavaScript object.
-///
-/// The properties of the JavaScript object are accessible via the `[]` and
-/// `[]=` operators. Methods are callable via [callMethod].
-class JsObject {
- // The wrapped JS object.
- final dynamic _jsObject;
-
- // This should only be called from _wrapToDart
- JsObject._fromJs(this._jsObject) {
- assert(_jsObject != null);
- }
-
- /// Constructs a JavaScript object from its native [constructor] and returns
- /// a proxy to it.
- factory JsObject(JsFunction constructor, [List arguments]) {
- var ctor = constructor._jsObject;
- if (arguments == null) {
- return _wrapToDart(JS('', 'new #()', ctor));
- }
- var unwrapped = List.from(arguments.map(_convertToJS));
- return _wrapToDart(JS('', 'new #(...#)', ctor, unwrapped));
- }
-
- /// Constructs a [JsObject] that proxies a native Dart object; _for expert use
- /// only_.
- ///
- /// Use this constructor only if you wish to get access to JavaScript
- /// properties attached to a browser host object, such as a Node or Blob, that
- /// is normally automatically converted into a native Dart object.
- ///
- /// An exception will be thrown if [object] either is `null` or has the type
- /// `bool`, `num`, or `String`.
- factory JsObject.fromBrowserObject(object) {
- if (object is num || object is String || object is bool || object == null) {
- throw ArgumentError("object cannot be a num, string, bool, or null");
- }
- return _wrapToDart(_convertToJS(object));
- }
-
- /// Recursively converts a JSON-like collection of Dart objects to a
- /// collection of JavaScript objects and returns a [JsObject] proxy to it.
- ///
- /// [object] must be a [Map] or [Iterable], the contents of which are also
- /// converted. Maps and Iterables are copied to a new JavaScript object.
- /// Primitives and other transferable values are directly converted to their
- /// JavaScript type, and all other objects are proxied.
- factory JsObject.jsify(object) {
- if ((object is! Map) && (object is! Iterable)) {
- throw ArgumentError("object must be a Map or Iterable");
- }
- return _wrapToDart(_convertDataTree(object));
- }
-
- static _convertDataTree(data) {
- var _convertedObjects = HashMap.identity();
-
- _convert(o) {
- if (_convertedObjects.containsKey(o)) {
- return _convertedObjects[o];
- }
- if (o is Map) {
- final convertedMap = JS('', '{}');
- _convertedObjects[o] = convertedMap;
- for (var key in o.keys) {
- JS('', '#[#] = #', convertedMap, key, _convert(o[key]));
- }
- return convertedMap;
- } else if (o is Iterable) {
- var convertedList = [];
- _convertedObjects[o] = convertedList;
- convertedList.addAll(o.map(_convert));
- return convertedList;
- } else {
- return _convertToJS(o);
- }
- }
-
- return _convert(data);
- }
-
- /// Returns the value associated with [property] from the proxied JavaScript
- /// object.
- ///
- /// The type of [property] must be either [String] or [num].
- dynamic operator [](Object property) {
- if (property is! String && property is! num) {
- throw ArgumentError("property is not a String or num");
- }
- return _convertToDart(JS('', '#[#]', _jsObject, property));
- }
-
- // Sets the value associated with [property] on the proxied JavaScript
- // object.
- //
- // The type of [property] must be either [String] or [num].
- void operator []=(Object property, value) {
- if (property is! String && property is! num) {
- throw ArgumentError("property is not a String or num");
- }
- JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
- }
-
- int get hashCode => 0;
-
- bool operator ==(other) =>
- other is JsObject && JS<bool>('!', '# === #', _jsObject, other._jsObject);
-
- /// Returns `true` if the JavaScript object contains the specified property
- /// either directly or though its prototype chain.
- ///
- /// This is the equivalent of the `in` operator in JavaScript.
- bool hasProperty(property) {
- if (property is! String && property is! num) {
- throw ArgumentError("property is not a String or num");
- }
- return JS<bool>('!', '# in #', property, _jsObject);
- }
-
- /// Removes [property] from the JavaScript object.
- ///
- /// This is the equivalent of the `delete` operator in JavaScript.
- void deleteProperty(property) {
- if (property is! String && property is! num) {
- throw ArgumentError("property is not a String or num");
- }
- JS<bool>('!', 'delete #[#]', _jsObject, property);
- }
-
- /// Returns `true` if the JavaScript object has [type] in its prototype chain.
- ///
- /// This is the equivalent of the `instanceof` operator in JavaScript.
- bool instanceof(JsFunction type) {
- return JS<bool>('!', '# instanceof #', _jsObject, _convertToJS(type));
- }
-
- /// Returns the result of the JavaScript objects `toString` method.
- String toString() {
- try {
- return JS<String>('!', 'String(#)', _jsObject);
- } catch (e) {
- return super.toString();
- }
- }
-
- /// Calls [method] on the JavaScript object with the arguments [args] and
- /// returns the result.
- ///
- /// The type of [method] must be either [String] or [num].
- dynamic callMethod(method, [List args]) {
- if (method is! String && method is! num) {
- throw ArgumentError("method is not a String or num");
- }
- if (args != null) args = List.from(args.map(_convertToJS));
- var fn = JS('', '#[#]', _jsObject, method);
- if (JS<bool>('!', 'typeof(#) !== "function"', fn)) {
- throw NoSuchMethodError(_jsObject, Symbol(method), args, {});
- }
- return _convertToDart(JS('', '#.apply(#, #)', fn, _jsObject, args));
- }
-}
-
-/// A proxy on a JavaScript Function object.
-class JsFunction extends JsObject {
- /// Returns a [JsFunction] that captures its 'this' binding and calls [f]
- /// with the value of JavaScript `this` passed as the first argument.
- factory JsFunction.withThis(Function f) {
- return JsFunction._fromJs(JS(
- '',
- 'function(/*...arguments*/) {'
- ' let args = [#(this)];'
- ' for (let arg of arguments) {'
- ' args.push(#(arg));'
- ' }'
- ' return #(#(...args));'
- '}',
- _convertToDart,
- _convertToDart,
- _convertToJS,
- f));
- }
-
- JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
-
- /// Invokes the JavaScript function with arguments [args]. If [thisArg] is
- /// supplied it is the value of `this` for the invocation.
- dynamic apply(List args, {thisArg}) => _convertToDart(JS(
- '',
- '#.apply(#, #)',
- _jsObject,
- _convertToJS(thisArg),
- args == null ? null : List.from(args.map(_convertToJS))));
-}
-
-// TODO(jmesserly): this is totally unnecessary in dev_compiler.
-/// A [List] that proxies a JavaScript array.
-class JsArray<E> extends JsObject with ListMixin<E> {
- /// Creates an empty JavaScript array.
- JsArray() : super._fromJs([]);
-
- /// Creates a new JavaScript array and initializes it to the contents of
- /// [other].
- JsArray.from(Iterable<E> other)
- : super._fromJs([]..addAll(other.map(_convertToJS)));
-
- JsArray._fromJs(jsObject) : super._fromJs(jsObject);
-
- _checkIndex(int index) {
- if (index is int && (index < 0 || index >= length)) {
- throw RangeError.range(index, 0, length);
- }
- }
-
- _checkInsertIndex(int index) {
- if (index is int && (index < 0 || index >= length + 1)) {
- throw RangeError.range(index, 0, length);
- }
- }
-
- static _checkRange(int start, int end, int length) {
- if (start < 0 || start > length) {
- throw RangeError.range(start, 0, length);
- }
- if (end < start || end > length) {
- throw RangeError.range(end, start, length);
- }
- }
-
- // Methods required by ListMixin
-
- E operator [](Object index) {
- // TODO(justinfagnani): fix the semantics for non-ints
- // dartbug.com/14605
- if (index is num && index == index.toInt()) {
- _checkIndex(index);
- }
- return super[index] as E;
- }
-
- void operator []=(Object index, value) {
- // TODO(justinfagnani): fix the semantics for non-ints
- // dartbug.com/14605
- if (index is num && index == index.toInt()) {
- _checkIndex(index);
- }
- super[index] = value;
- }
-
- int get length {
- // Check the length honours the List contract.
- var len = JS('', '#.length', _jsObject);
- // JavaScript arrays have lengths which are unsigned 32-bit integers.
- if (JS<bool>(
- '!', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
- return JS<int>('!', '#', len);
- }
- throw StateError('Bad JsArray length');
- }
-
- void set length(int length) {
- super['length'] = length;
- }
-
- // Methods overridden for better performance
-
- void add(E value) {
- callMethod('push', [value]);
- }
-
- void addAll(Iterable<E> iterable) {
- var list = (JS<bool>('!', '# instanceof Array', iterable))
- ? iterable
- : List.from(iterable);
- callMethod('push', list);
- }
-
- void insert(int index, E element) {
- _checkInsertIndex(index);
- callMethod('splice', [index, 0, element]);
- }
-
- E removeAt(int index) {
- _checkIndex(index);
- return callMethod('splice', [index, 1])[0] as E;
- }
-
- E removeLast() {
- if (length == 0) throw RangeError(-1);
- return callMethod('pop') as E;
- }
-
- void removeRange(int start, int end) {
- _checkRange(start, end, length);
- callMethod('splice', [start, end - start]);
- }
-
- void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
- _checkRange(start, end, this.length);
- int length = end - start;
- if (length == 0) return;
- if (skipCount < 0) throw ArgumentError(skipCount);
- var args = <Object>[start, length]
- ..addAll(iterable.skip(skipCount).take(length));
- callMethod('splice', args);
- }
-
- void sort([int compare(E a, E b)]) {
- // Note: arr.sort(null) is a type error in FF
- callMethod('sort', compare == null ? [] : [compare]);
- }
-}
-
-// Cross frame objects should not be considered browser types.
-// We include the instanceof Object test to filter out cross frame objects
-// on FireFox. Surprisingly on FireFox the instanceof Window test succeeds for
-// cross frame windows while the instanceof Object test fails.
-bool _isBrowserType(o) => JS(
- 'bool',
- '# instanceof Object && ('
- '# instanceof Blob || '
- '# instanceof Event || '
- '(window.KeyRange && # instanceof KeyRange) || '
- '(window.IDBKeyRange && # instanceof IDBKeyRange) || '
- '# instanceof ImageData || '
- '# instanceof Node || '
- // Int8Array.__proto__ is TypedArray.
- '(window.Int8Array && # instanceof Int8Array.__proto__) || '
- '# instanceof Window)',
- o,
- o,
- o,
- o,
- o,
- o,
- o,
- o,
- o);
-
-class _DartObject {
- final _dartObj;
- _DartObject(this._dartObj);
-}
-
-dynamic _convertToJS(dynamic o) {
- if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
- return o;
- } else if (o is DateTime) {
- return Primitives.lazyAsJsDate(o);
- } else if (o is JsObject) {
- return o._jsObject;
- } else if (o is Function) {
- return _putIfAbsent(_jsProxies, o, _wrapDartFunction);
- } else {
- // TODO(jmesserly): for now, we wrap other objects, to keep compatibility
- // with the original dart:js behavior.
- return _putIfAbsent(_jsProxies, o, (o) => _DartObject(o));
- }
-}
-
-dynamic _wrapDartFunction(f) {
- var wrapper = JS(
- '',
- 'function(/*...arguments*/) {'
- ' let args = Array.prototype.map.call(arguments, #);'
- ' return #(#(...args));'
- '}',
- _convertToDart,
- _convertToJS,
- f);
- JS('', '#.set(#, #)', _dartProxies, wrapper, f);
-
- return wrapper;
-}
-
-// converts a Dart object to a reference to a native JS object
-// which might be a DartObject JS->Dart proxy
-Object _convertToDart(o) {
- if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
- return o;
- } else if (JS('!', '# instanceof Date', o)) {
- num ms = JS('!', '#.getTime()', o);
- return DateTime.fromMillisecondsSinceEpoch(ms);
- } else if (o is _DartObject &&
- !identical(dart.getReifiedType(o), dart.jsobject)) {
- return o._dartObj;
- } else {
- return _wrapToDart(o);
- }
-}
-
-Object _wrapToDart(o) => _putIfAbsent(_dartProxies, o, _wrapToDartHelper);
-
-Object _wrapToDartHelper(o) {
- if (JS<bool>('!', 'typeof # == "function"', o)) {
- return JsFunction._fromJs(o);
- }
- if (JS<bool>('!', '# instanceof Array', o)) {
- return JsArray._fromJs(o);
- }
- return JsObject._fromJs(o);
-}
-
-final _dartProxies = JS('', 'new WeakMap()');
-final _jsProxies = JS('', 'new WeakMap()');
-
-Object _putIfAbsent(weakMap, o, getValue(o)) {
- var value = JS('', '#.get(#)', weakMap, o);
- if (value == null) {
- value = getValue(o);
- JS('', '#.set(#, #)', weakMap, o, value);
- }
- return value;
-}
-
-Expando<dynamic> _interopExpando = Expando<dynamic>();
-
-/// Returns a wrapper around function [f] that can be called from JavaScript
-/// using `package:js` JavaScript interop.
-///
-/// The calling conventions in Dart2Js differ from JavaScript and so, by
-/// default, it is not possible to call a Dart function directly. Wrapping with
-/// `allowInterop` creates a function that can be called from JavaScript or
-/// Dart. The semantics of the wrapped function are still more strict than
-/// JavaScript, and the function will throw if called with too many or too few
-/// arguments.
-///
-/// Calling this method repeatedly on a function will return the same result.
-F allowInterop<F extends Function>(F f) {
- if (!dart.isDartFunction(f)) return f;
- var ret = _interopExpando[f];
- if (ret == null) {
- ret = JS(
- '',
- 'function (...args) {'
- ' return #(#, args);'
- '}',
- dart.dcall,
- f);
- _interopExpando[f] = ret;
- }
- return ret;
-}
-
-Expando<Function> _interopCaptureThisExpando = Expando<Function>();
-
-/// Returns a wrapper around function [f] that can be called from JavaScript
-/// using `package:js` JavaScript interop, passing JavaScript `this` as the first
-/// argument.
-///
-/// See [allowInterop].
-///
-/// When called from Dart, [null] will be passed as the first argument.
-Function allowInteropCaptureThis(Function f) {
- if (!dart.isDartFunction(f)) return f;
- var ret = _interopCaptureThisExpando[f];
- if (ret == null) {
- ret = JS(
- '',
- 'function(...arguments) {'
- ' let args = [this];'
- ' args.push.apply(args, arguments);'
- ' return #(#, args);'
- '}',
- dart.dcall,
- f);
- _interopCaptureThisExpando[f] = ret;
- }
- return ret;
-}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/js_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/js_patch.dart
new file mode 100644
index 0000000..e0c10e8
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/js_patch.dart
@@ -0,0 +1,443 @@
+// 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.6
+
+// Patch file for dart:js library.
+library dart.js;
+
+import 'dart:collection' show HashMap, ListMixin;
+
+import 'dart:_js_helper' show patch, Primitives;
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+@patch
+JsObject get context => _context;
+
+final JsObject _context = _wrapToDart(dart.global_);
+
+@patch
+class JsObject {
+ // The wrapped JS object.
+ final dynamic _jsObject;
+
+ // This should only be called from _wrapToDart
+ JsObject._fromJs(this._jsObject) {
+ assert(_jsObject != null);
+ }
+
+ @patch
+ factory JsObject(JsFunction constructor, [List arguments]) {
+ var ctor = constructor._jsObject;
+ if (arguments == null) {
+ return _wrapToDart(JS('', 'new #()', ctor));
+ }
+ var unwrapped = List.from(arguments.map(_convertToJS));
+ return _wrapToDart(JS('', 'new #(...#)', ctor, unwrapped));
+ }
+
+ @patch
+ factory JsObject.fromBrowserObject(object) {
+ if (object is num || object is String || object is bool || object == null) {
+ throw ArgumentError("object cannot be a num, string, bool, or null");
+ }
+ return _wrapToDart(_convertToJS(object));
+ }
+
+ @patch
+ factory JsObject.jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw ArgumentError("object must be a Map or Iterable");
+ }
+ return _wrapToDart(_convertDataTree(object));
+ }
+
+ static _convertDataTree(data) {
+ var _convertedObjects = HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('', '#[#] = #', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return _convertToJS(o);
+ }
+ }
+
+ return _convert(data);
+ }
+
+ @patch
+ dynamic operator [](Object property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ return _convertToDart(JS('', '#[#]', _jsObject, property));
+ }
+
+ @patch
+ void operator []=(Object property, value) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
+ }
+
+ @patch
+ bool operator ==(other) =>
+ other is JsObject && JS<bool>('!', '# === #', _jsObject, other._jsObject);
+
+ @patch
+ bool hasProperty(property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ return JS<bool>('!', '# in #', property, _jsObject);
+ }
+
+ @patch
+ void deleteProperty(property) {
+ if (property is! String && property is! num) {
+ throw ArgumentError("property is not a String or num");
+ }
+ JS<bool>('!', 'delete #[#]', _jsObject, property);
+ }
+
+ @patch
+ bool instanceof(JsFunction type) {
+ return JS<bool>('!', '# instanceof #', _jsObject, _convertToJS(type));
+ }
+
+ @patch
+ String toString() {
+ try {
+ return JS<String>('!', 'String(#)', _jsObject);
+ } catch (e) {
+ return super.toString();
+ }
+ }
+
+ @patch
+ dynamic callMethod(method, [List args]) {
+ if (method is! String && method is! num) {
+ throw ArgumentError("method is not a String or num");
+ }
+ if (args != null) args = List.from(args.map(_convertToJS));
+ var fn = JS('', '#[#]', _jsObject, method);
+ if (JS<bool>('!', 'typeof(#) !== "function"', fn)) {
+ throw NoSuchMethodError(_jsObject, Symbol(method), args, {});
+ }
+ return _convertToDart(JS('', '#.apply(#, #)', fn, _jsObject, args));
+ }
+}
+
+@patch
+class JsFunction extends JsObject {
+ @patch
+ factory JsFunction.withThis(Function f) {
+ return JsFunction._fromJs(JS(
+ '',
+ 'function(/*...arguments*/) {'
+ ' let args = [#(this)];'
+ ' for (let arg of arguments) {'
+ ' args.push(#(arg));'
+ ' }'
+ ' return #(#(...args));'
+ '}',
+ _convertToDart,
+ _convertToDart,
+ _convertToJS,
+ f));
+ }
+
+ JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
+
+ @patch
+ dynamic apply(List args, {thisArg}) => _convertToDart(JS(
+ '',
+ '#.apply(#, #)',
+ _jsObject,
+ _convertToJS(thisArg),
+ args == null ? null : List.from(args.map(_convertToJS))));
+}
+
+// TODO(jmesserly): this is totally unnecessary in dev_compiler.
+@patch
+class JsArray<E> extends JsObject with ListMixin<E> {
+ @patch
+ factory JsArray() => JsArray<E>._fromJs([]);
+
+ @patch
+ factory JsArray.from(Iterable<E> other) =>
+ JsArray<E>._fromJs([]..addAll(other.map(_convertToJS)));
+
+ JsArray._fromJs(jsObject) : super._fromJs(jsObject);
+
+ _checkIndex(int index) {
+ if (index is int && (index < 0 || index >= length)) {
+ throw RangeError.range(index, 0, length);
+ }
+ }
+
+ _checkInsertIndex(int index) {
+ if (index is int && (index < 0 || index >= length + 1)) {
+ throw RangeError.range(index, 0, length);
+ }
+ }
+
+ static _checkRange(int start, int end, int length) {
+ if (start < 0 || start > length) {
+ throw RangeError.range(start, 0, length);
+ }
+ if (end < start || end > length) {
+ throw RangeError.range(end, start, length);
+ }
+ }
+
+ @patch
+ E operator [](Object index) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ return super[index] as E;
+ }
+
+ @patch
+ void operator []=(Object index, value) {
+ // TODO(justinfagnani): fix the semantics for non-ints
+ // dartbug.com/14605
+ if (index is num && index == index.toInt()) {
+ _checkIndex(index);
+ }
+ super[index] = value;
+ }
+
+ @patch
+ int get length {
+ // Check the length honours the List contract.
+ var len = JS('', '#.length', _jsObject);
+ // JavaScript arrays have lengths which are unsigned 32-bit integers.
+ if (JS<bool>(
+ '!', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
+ return JS<int>('!', '#', len);
+ }
+ throw StateError('Bad JsArray length');
+ }
+
+ @patch
+ void set length(int length) {
+ super['length'] = length;
+ }
+
+ @patch
+ void add(E value) {
+ callMethod('push', [value]);
+ }
+
+ @patch
+ void addAll(Iterable<E> iterable) {
+ var list = (JS<bool>('!', '# instanceof Array', iterable))
+ ? iterable
+ : List.from(iterable);
+ callMethod('push', list);
+ }
+
+ @patch
+ void insert(int index, E element) {
+ _checkInsertIndex(index);
+ callMethod('splice', [index, 0, element]);
+ }
+
+ @patch
+ E removeAt(int index) {
+ _checkIndex(index);
+ return callMethod('splice', [index, 1])[0] as E;
+ }
+
+ @patch
+ E removeLast() {
+ if (length == 0) throw RangeError(-1);
+ return callMethod('pop') as E;
+ }
+
+ @patch
+ void removeRange(int start, int end) {
+ _checkRange(start, end, length);
+ callMethod('splice', [start, end - start]);
+ }
+
+ @patch
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ _checkRange(start, end, this.length);
+ int length = end - start;
+ if (length == 0) return;
+ if (skipCount < 0) throw ArgumentError(skipCount);
+ var args = <Object>[start, length]
+ ..addAll(iterable.skip(skipCount).take(length));
+ callMethod('splice', args);
+ }
+
+ @patch
+ void sort([int compare(E a, E b)]) {
+ // Note: arr.sort(null) is a type error in FF
+ callMethod('sort', compare == null ? [] : [compare]);
+ }
+}
+
+// Cross frame objects should not be considered browser types.
+// We include the instanceof Object test to filter out cross frame objects
+// on FireFox. Surprisingly on FireFox the instanceof Window test succeeds for
+// cross frame windows while the instanceof Object test fails.
+bool _isBrowserType(o) => JS(
+ 'bool',
+ '# instanceof Object && ('
+ '# instanceof Blob || '
+ '# instanceof Event || '
+ '(window.KeyRange && # instanceof KeyRange) || '
+ '(window.IDBKeyRange && # instanceof IDBKeyRange) || '
+ '# instanceof ImageData || '
+ '# instanceof Node || '
+ // Int8Array.__proto__ is TypedArray.
+ '(window.Int8Array && # instanceof Int8Array.__proto__) || '
+ '# instanceof Window)',
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o,
+ o);
+
+class _DartObject {
+ final _dartObj;
+ _DartObject(this._dartObj);
+}
+
+dynamic _convertToJS(dynamic o) {
+ if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+ return o;
+ } else if (o is DateTime) {
+ return Primitives.lazyAsJsDate(o);
+ } else if (o is JsObject) {
+ return o._jsObject;
+ } else if (o is Function) {
+ return _putIfAbsent(_jsProxies, o, _wrapDartFunction);
+ } else {
+ // TODO(jmesserly): for now, we wrap other objects, to keep compatibility
+ // with the original dart:js behavior.
+ return _putIfAbsent(_jsProxies, o, (o) => _DartObject(o));
+ }
+}
+
+dynamic _wrapDartFunction(f) {
+ var wrapper = JS(
+ '',
+ 'function(/*...arguments*/) {'
+ ' let args = Array.prototype.map.call(arguments, #);'
+ ' return #(#(...args));'
+ '}',
+ _convertToDart,
+ _convertToJS,
+ f);
+ JS('', '#.set(#, #)', _dartProxies, wrapper, f);
+
+ return wrapper;
+}
+
+// converts a Dart object to a reference to a native JS object
+// which might be a DartObject JS->Dart proxy
+Object _convertToDart(o) {
+ if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
+ return o;
+ } else if (JS('!', '# instanceof Date', o)) {
+ num ms = JS('!', '#.getTime()', o);
+ return DateTime.fromMillisecondsSinceEpoch(ms);
+ } else if (o is _DartObject &&
+ !identical(dart.getReifiedType(o), dart.jsobject)) {
+ return o._dartObj;
+ } else {
+ return _wrapToDart(o);
+ }
+}
+
+Object _wrapToDart(o) => _putIfAbsent(_dartProxies, o, _wrapToDartHelper);
+
+Object _wrapToDartHelper(o) {
+ if (JS<bool>('!', 'typeof # == "function"', o)) {
+ return JsFunction._fromJs(o);
+ }
+ if (JS<bool>('!', '# instanceof Array', o)) {
+ return JsArray._fromJs(o);
+ }
+ return JsObject._fromJs(o);
+}
+
+final _dartProxies = JS('', 'new WeakMap()');
+final _jsProxies = JS('', 'new WeakMap()');
+
+Object _putIfAbsent(weakMap, o, getValue(o)) {
+ var value = JS('', '#.get(#)', weakMap, o);
+ if (value == null) {
+ value = getValue(o);
+ JS('', '#.set(#, #)', weakMap, o, value);
+ }
+ return value;
+}
+
+Expando<Function> _interopExpando = Expando<Function>();
+
+@patch
+F allowInterop<F extends Function>(F f) {
+ if (!dart.isDartFunction(f)) return f;
+ var ret = _interopExpando[f];
+ if (ret == null) {
+ ret = JS(
+ '',
+ 'function (...args) {'
+ ' return #(#, args);'
+ '}',
+ dart.dcall,
+ f);
+ _interopExpando[f] = ret;
+ }
+ return ret;
+}
+
+Expando<Function> _interopCaptureThisExpando = Expando<Function>();
+
+@patch
+Function allowInteropCaptureThis(Function f) {
+ if (!dart.isDartFunction(f)) return f;
+ var ret = _interopCaptureThisExpando[f];
+ if (ret == null) {
+ ret = JS(
+ '',
+ 'function(...arguments) {'
+ ' let args = [this];'
+ ' args.push.apply(args, arguments);'
+ ' return #(#, args);'
+ '}',
+ dart.dcall,
+ f);
+ _interopCaptureThisExpando[f] = ret;
+ }
+ return ret;
+}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
index adfae9f..357047e 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
@@ -106,9 +106,7 @@
*/
// Add additional optional arguments if needed. The method is treated internally
// as a variable argument method.
-// TODO(vsm): Make this `T extends Object?` when
-// https://github.com/dart-lang/sdk/issues/40022 is fixed.
-T JS<T>(String typeDescription, String codeTemplate,
+T JS<T extends Object?>(String typeDescription, String codeTemplate,
[arg0,
arg1,
arg2,
diff --git a/sdk_nnbd/lib/js/dart2js/js_dart2js.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_patch.dart
similarity index 67%
copy from sdk_nnbd/lib/js/dart2js/js_dart2js.dart
copy to sdk_nnbd/lib/_internal/js_runtime/lib/js_patch.dart
index 4155113..ab4a332 100644
--- a/sdk_nnbd/lib/js/dart2js/js_dart2js.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_patch.dart
@@ -1,109 +1,22 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// 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
+// @dart = 2.6
-/// Low-level support for interoperating with JavaScript.
-///
-/// You should usually use `package:js` instead of this library. For more
-/// information, see the [JS interop page](https://dart.dev/web/js-interop).
-///
-/// This library provides access to JavaScript objects from Dart, allowing
-/// Dart code to get and set properties, and call methods of JavaScript objects
-/// and invoke JavaScript functions. The library takes care of converting
-/// between Dart and JavaScript objects where possible, or providing proxies if
-/// conversion isn't possible.
-///
-/// This library does not make Dart objects usable from JavaScript, their
-/// methods and properties are not accessible, though it does allow Dart
-/// functions to be passed into and called from JavaScript.
-///
-/// [JsObject] is the core type and represents a proxy of a JavaScript object.
-/// JsObject gives access to the underlying JavaScript objects properties and
-/// methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
-/// created from proxies to JavaScript constructors.
-///
-/// The top-level getter [context] provides a [JsObject] that represents the
-/// global object in JavaScript, usually `window`.
-///
-/// The following example shows an alert dialog via a JavaScript call to the
-/// global function `alert()`:
-///
-/// import 'dart:js';
-///
-/// main() => context.callMethod('alert', ['Hello from Dart!']);
-///
-/// This example shows how to create a [JsObject] from a JavaScript constructor
-/// and access its properties:
-///
-/// import 'dart:js';
-///
-/// main() {
-/// var object = JsObject(context['Object']);
-/// object['greeting'] = 'Hello';
-/// object['greet'] = (name) => "${object['greeting']} $name";
-/// var message = object.callMethod('greet', ['JavaScript']);
-/// context['console'].callMethod('log', [message]);
-/// }
-///
-/// ## Proxying and automatic conversion
-///
-/// When setting properties on a JsObject or passing arguments to a Javascript
-/// method or function, Dart objects are automatically converted or proxied to
-/// JavaScript objects. When accessing JavaScript properties, or when a Dart
-/// closure is invoked from JavaScript, the JavaScript objects are also
-/// converted to Dart.
-///
-/// Functions and closures are proxied in such a way that they are callable. A
-/// Dart closure assigned to a JavaScript property is proxied by a function in
-/// JavaScript. A JavaScript function accessed from Dart is proxied by a
-/// [JsFunction], which has a [apply] method to invoke it.
-///
-/// The following types are transferred directly and not proxied:
-///
-/// * Basic types: `null`, `bool`, `num`, `String`, `DateTime`
-/// * `TypedData`, including its subclasses like `Int32List`, but _not_
-/// `ByteBuffer`
-/// * When compiling for the web, also: `Blob`, `Event`, `ImageData`,
-/// `KeyRange`, `Node`, and `Window`.
-///
-/// ## Converting collections with JsObject.jsify()
-///
-/// To create a JavaScript collection from a Dart collection use the
-/// [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
-/// into JavaScript Objects and Arrays.
-///
-/// The following expression creates a new JavaScript object with the properties
-/// `a` and `b` defined:
-///
-/// var jsMap = JsObject.jsify({'a': 1, 'b': 2});
-///
-/// This expression creates a JavaScript array:
-///
-/// var jsArray = JsObject.jsify([1, 2, 3]);
-///
-/// {@category Web}
-library dart.js;
-
+// Patch file for dart:js library.
import 'dart:collection' show HashMap, ListMixin;
import 'dart:typed_data' show TypedData;
-import 'dart:_foreign_helper' show JS, JS_CONST, DART_CLOSURE_TO_JS;
-import 'dart:_interceptors'
- show
- JavaScriptFunction,
- JavaScriptObject,
- UnknownJavaScriptObject,
- DART_CLOSURE_PROPERTY_NAME;
-import 'dart:_js_helper'
- show Primitives, convertDartClosureToJS, getIsolateAffinityTag;
+import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS;
+import 'dart:_interceptors' show JavaScriptFunction, DART_CLOSURE_PROPERTY_NAME;
+import 'dart:_js_helper' show patch, Primitives, getIsolateAffinityTag;
import 'dart:_js' show isBrowserObject, convertFromBrowserObject;
-export 'dart:_interceptors' show JavaScriptObject;
+@patch
+JsObject get context => _context;
-/// The JavaScript global object, usually `window`.
-final JsObject context = _wrapToDart(JS('', 'self'));
+final JsObject _context = _wrapToDart(JS('', 'self'));
_convertDartFunction(Function f, {bool captureThis: false}) {
return JS(
@@ -129,10 +42,7 @@
return _convertToJS(Function.apply(callback, dartArgs));
}
-/// A proxy on a JavaScript object.
-///
-/// The properties of the JavaScript object are accessible via the `[]` and
-/// `[]=` operators. Methods are callable via [callMethod].
+@patch
class JsObject {
// The wrapped JS object.
final dynamic _jsObject;
@@ -142,8 +52,7 @@
assert(_jsObject != null);
}
- /// Constructs a JavaScript object from its native [constructor] and returns
- /// a proxy to it.
+ @patch
factory JsObject(JsFunction constructor, [List arguments]) {
var ctor = _convertToJS(constructor);
if (arguments == null) {
@@ -206,15 +115,7 @@
// return _wrapToDart(jsObj);
}
- /// Constructs a [JsObject] that proxies a native Dart object; _for expert use
- /// only_.
- ///
- /// Use this constructor only if you wish to get access to JavaScript
- /// properties attached to a browser host object, such as a Node or Blob, that
- /// is normally automatically converted into a native Dart object.
- ///
- /// An exception will be thrown if [object] either is `null` or has the type
- /// `bool`, `num`, or `String`.
+ @patch
factory JsObject.fromBrowserObject(object) {
if (object is num || object is String || object is bool || object == null) {
throw ArgumentError("object cannot be a num, string, bool, or null");
@@ -222,13 +123,7 @@
return _wrapToDart(_convertToJS(object));
}
- /// Recursively converts a JSON-like collection of Dart objects to a
- /// collection of JavaScript objects and returns a [JsObject] proxy to it.
- ///
- /// [object] must be a [Map] or [Iterable], the contents of which are also
- /// converted. Maps and Iterables are copied to a new JavaScript object.
- /// Primitives and other transferable values are directly converted to their
- /// JavaScript type, and all other objects are proxied.
+ @patch
factory JsObject.jsify(object) {
if ((object is! Map) && (object is! Iterable)) {
throw ArgumentError("object must be a Map or Iterable");
@@ -263,10 +158,7 @@
return _convert(data);
}
- /// Returns the value associated with [property] from the proxied JavaScript
- /// object.
- ///
- /// The type of [property] must be either [String] or [num].
+ @patch
dynamic operator [](property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -274,10 +166,7 @@
return _convertToDart(JS('', '#[#]', _jsObject, property));
}
- // Sets the value associated with [property] on the proxied JavaScript
- // object.
- //
- // The type of [property] must be either [String] or [num].
+ @patch
void operator []=(property, value) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -285,15 +174,11 @@
JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
}
- int get hashCode => 0;
-
+ @patch
bool operator ==(other) =>
other is JsObject && JS('bool', '# === #', _jsObject, other._jsObject);
- /// Returns `true` if the JavaScript object contains the specified property
- /// either directly or though its prototype chain.
- ///
- /// This is the equivalent of the `in` operator in JavaScript.
+ @patch
bool hasProperty(property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -301,9 +186,7 @@
return JS('bool', '# in #', property, _jsObject);
}
- /// Removes [property] from the JavaScript object.
- ///
- /// This is the equivalent of the `delete` operator in JavaScript.
+ @patch
void deleteProperty(property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
@@ -311,14 +194,12 @@
JS('bool', 'delete #[#]', _jsObject, property);
}
- /// Returns `true` if the JavaScript object has [type] in its prototype chain.
- ///
- /// This is the equivalent of the `instanceof` operator in JavaScript.
+ @patch
bool instanceof(JsFunction type) {
return JS('bool', '# instanceof #', _jsObject, _convertToJS(type));
}
- /// Returns the result of the JavaScript objects `toString` method.
+ @patch
String toString() {
try {
return JS('String', 'String(#)', _jsObject);
@@ -327,10 +208,7 @@
}
}
- /// Calls [method] on the JavaScript object with the arguments [args] and
- /// returns the result.
- ///
- /// The type of [method] must be either [String] or [num].
+ @patch
dynamic callMethod(method, [List args]) {
if (method is! String && method is! num) {
throw ArgumentError("method is not a String or num");
@@ -340,10 +218,9 @@
}
}
-/// A proxy on a JavaScript Function object.
+@patch
class JsFunction extends JsObject {
- /// Returns a [JsFunction] that captures its 'this' binding and calls [f]
- /// with the value of JavaScript `this` passed as the first argument.
+ @patch
factory JsFunction.withThis(Function f) {
var jsFunc = _convertDartFunction(f, captureThis: true);
return JsFunction._fromJs(jsFunc);
@@ -351,8 +228,7 @@
JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
- /// Invokes the JavaScript function with arguments [args]. If [thisArg] is
- /// supplied it is the value of `this` for the invocation.
+ @patch
dynamic apply(List args, {thisArg}) => _convertToDart(JS(
'',
'#.apply(#, #)',
@@ -361,15 +237,14 @@
args == null ? null : List.from(args.map(_convertToJS))));
}
-/// A [List] that proxies a JavaScript array.
+@patch
class JsArray<E> extends JsObject with ListMixin<E> {
- /// Creates an empty JavaScript array.
- JsArray() : super._fromJs([]);
+ @patch
+ factory JsArray() => JsArray<E>._fromJs([]);
- /// Creates a new JavaScript array and initializes it to the contents of
- /// [other].
- JsArray.from(Iterable<E> other)
- : super._fromJs([]..addAll(other.map(_convertToJS)));
+ @patch
+ factory JsArray.from(Iterable<E> other) =>
+ JsArray<E>._fromJs([]..addAll(other.map(_convertToJS)));
JsArray._fromJs(jsObject) : super._fromJs(jsObject);
@@ -396,6 +271,7 @@
// Methods required by ListMixin
+ @patch
E operator [](dynamic index) {
// TODO(justinfagnani): fix the semantics for non-ints
// dartbug.com/14605
@@ -405,6 +281,7 @@
return super[index];
}
+ @patch
void operator []=(dynamic index, E value) {
// TODO(justinfagnani): fix the semantics for non-ints
// dartbug.com/14605
@@ -414,6 +291,7 @@
super[index] = value;
}
+ @patch
int get length {
// Check the length honours the List contract.
var len = JS('', '#.length', _jsObject);
@@ -424,16 +302,19 @@
throw StateError('Bad JsArray length');
}
+ @patch
void set length(int length) {
super['length'] = length;
}
// Methods overridden for better performance
+ @patch
void add(E value) {
callMethod('push', [value]);
}
+ @patch
void addAll(Iterable<E> iterable) {
var list = (JS('bool', '# instanceof Array', iterable))
? iterable
@@ -441,26 +322,31 @@
callMethod('push', list);
}
+ @patch
void insert(int index, E element) {
_checkInsertIndex(index);
callMethod('splice', [index, 0, element]);
}
+ @patch
E removeAt(int index) {
_checkIndex(index);
return callMethod('splice', [index, 1])[0];
}
+ @patch
E removeLast() {
if (length == 0) throw RangeError(-1);
return callMethod('pop');
}
+ @patch
void removeRange(int start, int end) {
_checkRange(start, end, length);
callMethod('splice', [start, end - start]);
}
+ @patch
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_checkRange(start, end, this.length);
int length = end - start;
@@ -471,6 +357,7 @@
callMethod('splice', args);
}
+ @patch
void sort([int compare(E a, E b)]) {
// Note: arr.sort(null) is a type error in FF
callMethod('sort', compare == null ? [] : [compare]);
@@ -659,17 +546,7 @@
return Function.apply(callback, [self]..addAll(arguments));
}
-/// Returns a wrapper around function [f] that can be called from JavaScript
-/// using `package:js` JavaScript interop.
-///
-/// The calling conventions in Dart2Js differ from JavaScript and so, by
-/// default, it is not possible to call a Dart function directly. Wrapping with
-/// `allowInterop` creates a function that can be called from JavaScript or
-/// Dart. The semantics of the wrapped function are still more strict than
-/// JavaScript, and the function will throw if called with too many or too few
-/// arguments.
-///
-/// Calling this method repeatedly on a function will return the same result.
+@patch
F allowInterop<F extends Function>(F f) {
if (JS('bool', 'typeof(#) == "function"', f)) {
// Already supports interop, just use the existing function.
@@ -679,13 +556,7 @@
}
}
-/// Returns a wrapper around function [f] that can be called from JavaScript
-/// using `package:js` JavaScript interop, passing JavaScript `this` as the first
-/// argument.
-///
-/// See [allowInterop].
-///
-/// When called from Dart, [null] will be passed as the first argument.
+@patch
Function allowInteropCaptureThis(Function f) {
if (JS('bool', 'typeof(#) == "function"', f)) {
// Behavior when the function is already a JS function is unspecified.
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
index ef985e2..ef4654b 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
@@ -16,7 +16,6 @@
JS_EMBEDDED_GLOBAL,
JS_GET_FLAG,
JS_GET_NAME,
- JS_STRING_CONCAT,
RAW_DART_FUNCTION_REF,
TYPE_REF;
@@ -789,7 +788,8 @@
var isFn = RAW_DART_FUNCTION_REF(_generalIsTestImplementation);
- if (isTopType(testRti)) {
+ // TODO(fishythefish): Update for NNBD.
+ if (isLegacyTopType(testRti)) {
isFn = RAW_DART_FUNCTION_REF(_isTop);
var asFn = RAW_DART_FUNCTION_REF(_asTop);
Rti._setAsCheckFunction(testRti, asFn);
@@ -811,7 +811,11 @@
String name = Rti._getInterfaceName(testRti);
var arguments = Rti._getInterfaceTypeArguments(testRti);
if (JS(
- 'bool', '#.every(#)', arguments, RAW_DART_FUNCTION_REF(isTopType))) {
+ 'bool',
+ '#.every(#)',
+ arguments,
+ // TODO(fishythefish): Update for NNBD.
+ RAW_DART_FUNCTION_REF(isLegacyTopType))) {
String propertyName =
'${JS_GET_NAME(JsGetName.OPERATOR_IS_PREFIX)}${name}';
Rti._setSpecializedTestResource(testRti, propertyName);
@@ -830,7 +834,8 @@
// method. The Rti object is 'this'.
Rti testRti = _castToRti(JS('', 'this'));
Rti objectRti = instanceOrFunctionType(object, testRti);
- return isSubtype(_theUniverse(), objectRti, testRti);
+ // TODO(fishythefish): Update for NNBD.
+ return isLegacySubtype(_theUniverse(), objectRti, testRti);
}
/// Called from generated code.
@@ -881,7 +886,8 @@
/// Called from generated code.
checkTypeBound(Rti type, Rti bound, variable, methodName) {
- if (isSubtype(_theUniverse(), type, bound)) return type;
+ // TODO(fishythefish): Update for NNBD.
+ if (isLegacySubtype(_theUniverse(), type, bound)) return type;
String message = "The type argument '${_rtiToString(type, null)}' is not"
" a subtype of the type variable bound '${_rtiToString(bound, null)}'"
" of type variable '${_Utils.asString(variable)}' in '$methodName'.";
@@ -1080,7 +1086,8 @@
typeParametersText += typeSep;
typeParametersText += genericContext[genericContext.length - 1 - i];
Rti boundRti = _castToRti(_Utils.arrayAt(bounds, i));
- if (!isTopType(boundRti)) {
+ // TODO(fishythefish): Update for NNBD.
+ if (!isLegacyTopType(boundRti)) {
typeParametersText +=
' extends ' + _rtiToString(boundRti, genericContext);
}
@@ -1470,7 +1477,6 @@
environment = Rti._getBindingBase(environment);
}
- assert(kind == Rti.kindInterface);
String interfaceName = Rti._getInterfaceName(environment);
Object rule = _Universe.findRule(universe, interfaceName);
assert(rule != null);
@@ -2310,49 +2316,63 @@
// -------- Subtype tests ------------------------------------------------------
// Future entry point from compiled code.
-bool isSubtype(universe, Rti s, Rti t) {
- return _isSubtype(universe, s, null, t, null);
+bool isLegacySubtype(universe, Rti s, Rti t) {
+ return _isSubtype(universe, s, null, t, null, true);
}
-bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
- // Based on
- // https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
- // and https://github.com/dart-lang/language/pull/388.
- // In particular, the bulk of the structure is derived from the former
- // resource, with a few adaptations taken from the latter.
- // - We freely skip subcases which would have already been handled by a
- // previous case.
- // - Some rules are reordered in conjunction with the previous point to reduce
- // the amount of casework.
- // - Left Type Variable Bound in particular is split into two pieces: an
- // optimistic check performed early in the algorithm to reduce the number of
- // backtracking cases when a union appears on the right, and a pessimistic
- // check performed at the usual place in order to completely eliminate the
- // case.
- // - Function type rules are applied before interface type rules.
+bool isNnbdSubtype(universe, Rti s, Rti t) {
+ return _isSubtype(universe, s, null, t, null, false);
+}
+/// Based on
+/// https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
+/// and https://github.com/dart-lang/language/pull/388.
+/// In particular, the bulk of the structure is derived from the former
+/// resource, with a few adaptations taken from the latter.
+/// - We freely skip subcases which would have already been handled by a
+/// previous case.
+/// - Some rules are reordered in conjunction with the previous point to reduce
+/// the amount of casework.
+/// - Left Type Variable Bound in particular is split into two pieces: an
+/// optimistic check performed early in the algorithm to reduce the number of
+/// backtracking cases when a union appears on the right, and a pessimistic
+/// check performed at the usual place in order to completely eliminate the
+/// case.
+/// - Function type rules are applied before interface type rules.
+///
+/// [s] is considered a legacy subtype of [t] if [s] would be a subtype of [t]
+/// in a modification of the NNBD rules in which `?` on types were ignored, `*`
+/// were added to each time, and `required` parameters were treated as
+/// optional. In effect, `Never` is equivalent to `Null`, `Null` is restored to
+/// the bottom of the type hierarchy, `Object` is treated as nullable, and
+/// `required` is ignored on named parameters. This should provide the same
+/// subtyping results as pre-NNBD Dart.
+bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv, bool isLegacy) {
// Reflexivity:
if (_Utils.isIdentical(s, t)) return true;
// Right Top:
- if (isTopType(t)) return true;
+ if (isTopType(t, isLegacy)) return true;
int sKind = Rti._getKind(s);
if (sKind == Rti.kindAny) return true;
// Left Top:
- if (isTopType(s)) return false;
+ if (isTopType(s, isLegacy)) return false;
// Left Bottom:
- // TODO(fishythefish): Update for NNBD - check for `Never` instead of `Null`.
- if (isNullType(s)) return true;
+ if (isLegacy) {
+ if (isNullType(s)) return true;
+ } else {
+ if (sKind == Rti.kindNever) return true;
+ }
// Left Type Variable Bound 1:
bool leftTypeVariable = sKind == Rti.kindGenericFunctionParameter;
if (leftTypeVariable) {
int index = Rti._getGenericFunctionParameterIndex(s);
Rti bound = _castToRti(_Utils.arrayAt(sEnv, index));
- if (_isSubtype(universe, bound, sEnv, t, tEnv)) return true;
+ if (_isSubtype(universe, bound, sEnv, t, tEnv, isLegacy)) return true;
}
int tKind = Rti._getKind(t);
@@ -2360,48 +2380,62 @@
// Left Null:
// Note: Interchanging the Left Null and Right Object rules allows us to
// reduce casework.
- if (isNullType(s)) {
+ if (!isLegacy && isNullType(s)) {
if (tKind == Rti.kindFutureOr) {
- return _isSubtype(universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv);
+ return _isSubtype(
+ universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv, isLegacy);
}
return isNullType(t) || tKind == Rti.kindQuestion || tKind == Rti.kindStar;
}
// Right Object:
- if (isObjectType(t)) {
+ if (!isLegacy && isObjectType(t)) {
if (sKind == Rti.kindFutureOr) {
- return _isSubtype(universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv);
+ return _isSubtype(
+ universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv, isLegacy);
}
if (sKind == Rti.kindStar) {
- return _isSubtype(universe, Rti._getStarArgument(s), sEnv, t, tEnv);
+ return _isSubtype(
+ universe, Rti._getStarArgument(s), sEnv, t, tEnv, isLegacy);
}
return sKind != Rti.kindQuestion;
}
// Left Legacy:
if (sKind == Rti.kindStar) {
- return _isSubtype(universe, Rti._getStarArgument(s), sEnv, t, tEnv);
+ return _isSubtype(
+ universe, Rti._getStarArgument(s), sEnv, t, tEnv, isLegacy);
}
// Right Legacy:
if (tKind == Rti.kindStar) {
return _isSubtype(
- universe, s, sEnv, Rti._getQuestionFromStar(universe, t), tEnv);
+ universe,
+ s,
+ sEnv,
+ isLegacy
+ ? Rti._getStarArgument(t)
+ : Rti._getQuestionFromStar(universe, t),
+ tEnv,
+ isLegacy);
}
// Left FutureOr:
if (sKind == Rti.kindFutureOr) {
- if (!_isSubtype(universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv)) {
+ if (!_isSubtype(
+ universe, Rti._getFutureOrArgument(s), sEnv, t, tEnv, isLegacy)) {
return false;
}
- return _isSubtype(
- universe, Rti._getFutureFromFutureOr(universe, s), sEnv, t, tEnv);
+ return _isSubtype(universe, Rti._getFutureFromFutureOr(universe, s), sEnv,
+ t, tEnv, isLegacy);
}
// Left Nullable:
if (sKind == Rti.kindQuestion) {
- return _isSubtype(universe, TYPE_REF<Null>(), sEnv, t, tEnv) &&
- _isSubtype(universe, Rti._getQuestionArgument(s), sEnv, t, tEnv);
+ return (isLegacy ||
+ _isSubtype(universe, TYPE_REF<Null>(), sEnv, t, tEnv, isLegacy)) &&
+ _isSubtype(
+ universe, Rti._getQuestionArgument(s), sEnv, t, tEnv, isLegacy);
}
// Type Variable Reflexivity 1 is subsumed by Reflexivity and therefore
@@ -2411,17 +2445,20 @@
// Right FutureOr:
if (tKind == Rti.kindFutureOr) {
- if (_isSubtype(universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv)) {
+ if (_isSubtype(
+ universe, s, sEnv, Rti._getFutureOrArgument(t), tEnv, isLegacy)) {
return true;
}
- return _isSubtype(
- universe, s, sEnv, Rti._getFutureFromFutureOr(universe, t), tEnv);
+ return _isSubtype(universe, s, sEnv,
+ Rti._getFutureFromFutureOr(universe, t), tEnv, isLegacy);
}
// Right Nullable:
if (tKind == Rti.kindQuestion) {
- return _isSubtype(universe, s, sEnv, TYPE_REF<Null>(), tEnv) ||
- _isSubtype(universe, s, sEnv, Rti._getQuestionArgument(t), tEnv);
+ return (!isLegacy &&
+ _isSubtype(universe, s, sEnv, TYPE_REF<Null>(), tEnv, isLegacy)) ||
+ _isSubtype(
+ universe, s, sEnv, Rti._getQuestionArgument(t), tEnv, isLegacy);
}
// Left Promoted Variable does not apply at runtime.
@@ -2444,37 +2481,39 @@
var sBounds = Rti._getGenericFunctionBounds(s);
var tBounds = Rti._getGenericFunctionBounds(t);
- if (!typesEqual(sBounds, tBounds)) return false;
+ if (!typesEqual(sBounds, tBounds, isLegacy)) return false;
sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv);
tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv);
return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv,
- Rti._getGenericFunctionBase(t), tEnv);
+ Rti._getGenericFunctionBase(t), tEnv, isLegacy);
}
if (tKind == Rti.kindFunction) {
if (isJsFunctionType(s)) return true;
if (sKind != Rti.kindFunction) return false;
- return _isFunctionSubtype(universe, s, sEnv, t, tEnv);
+ return _isFunctionSubtype(universe, s, sEnv, t, tEnv, isLegacy);
}
// Interface Compositionality + Super-Interface:
if (sKind == Rti.kindInterface) {
if (tKind != Rti.kindInterface) return false;
- return _isInterfaceSubtype(universe, s, sEnv, t, tEnv);
+ return _isInterfaceSubtype(universe, s, sEnv, t, tEnv, isLegacy);
}
return false;
}
// TODO(fishythefish): Support required named parameters.
-bool _isFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+bool _isFunctionSubtype(universe, Rti s, sEnv, Rti t, tEnv, bool isLegacy) {
assert(Rti._getKind(s) == Rti.kindFunction);
assert(Rti._getKind(t) == Rti.kindFunction);
Rti sReturnType = Rti._getReturnType(s);
Rti tReturnType = Rti._getReturnType(t);
- if (!_isSubtype(universe, sReturnType, sEnv, tReturnType, tEnv)) return false;
+ if (!_isSubtype(universe, sReturnType, sEnv, tReturnType, tEnv, isLegacy)) {
+ return false;
+ }
_FunctionParameters sParameters = Rti._getFunctionParameters(s);
_FunctionParameters tParameters = Rti._getFunctionParameters(t);
@@ -2501,21 +2540,27 @@
for (int i = 0; i < sRequiredPositionalLength; i++) {
Rti sParameter = _castToRti(_Utils.arrayAt(sRequiredPositional, i));
Rti tParameter = _castToRti(_Utils.arrayAt(tRequiredPositional, i));
- if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv, isLegacy)) {
+ return false;
+ }
}
for (int i = 0; i < requiredPositionalDelta; i++) {
Rti sParameter = _castToRti(_Utils.arrayAt(sOptionalPositional, i));
Rti tParameter = _castToRti(
_Utils.arrayAt(tRequiredPositional, sRequiredPositionalLength + i));
- if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv, isLegacy)) {
+ return false;
+ }
}
for (int i = 0; i < tOptionalPositionalLength; i++) {
Rti sParameter = _castToRti(
_Utils.arrayAt(sOptionalPositional, requiredPositionalDelta + i));
Rti tParameter = _castToRti(_Utils.arrayAt(tOptionalPositional, i));
- if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv)) return false;
+ if (!_isSubtype(universe, tParameter, tEnv, sParameter, sEnv, isLegacy)) {
+ return false;
+ }
}
var sOptionalNamed = _FunctionParameters._getOptionalNamed(sParameters);
@@ -2534,13 +2579,13 @@
if (_Utils.stringLessThan(tName, sName)) return false;
Rti sType = _castToRti(_Utils.arrayAt(sOptionalNamed, i - 1));
Rti tType = _castToRti(_Utils.arrayAt(tOptionalNamed, j + 1));
- if (!_isSubtype(universe, tType, tEnv, sType, sEnv)) return false;
+ if (!_isSubtype(universe, tType, tEnv, sType, sEnv, isLegacy)) return false;
}
return true;
}
-bool _isInterfaceSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
+bool _isInterfaceSubtype(universe, Rti s, sEnv, Rti t, tEnv, bool isLegacy) {
String sName = Rti._getInterfaceName(s);
String tName = Rti._getInterfaceName(t);
@@ -2569,21 +2614,29 @@
switch (sVariance) {
case Variance.legacyCovariant:
case Variance.covariant:
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) return false;
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv, isLegacy)) {
+ return false;
+ }
break;
case Variance.contravariant:
- if (!_isSubtype(universe, tArg, tEnv, sArg, sEnv)) return false;
+ if (!_isSubtype(universe, tArg, tEnv, sArg, sEnv, isLegacy)) {
+ return false;
+ }
break;
case Variance.invariant:
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv) ||
- !_isSubtype(universe, tArg, tEnv, sArg, sEnv)) return false;
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv, isLegacy) ||
+ !_isSubtype(universe, tArg, tEnv, sArg, sEnv, isLegacy)) {
+ return false;
+ }
break;
default:
throw StateError(
"Unknown variance given for subtype check: $sVariance");
}
} else {
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) return false;
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv, isLegacy)) {
+ return false;
+ }
}
}
return true;
@@ -2610,7 +2663,9 @@
String recipe = _Utils.asString(_Utils.arrayAt(supertypeArgs, i));
Rti supertypeArg = _Universe.evalInEnvironment(universe, s, recipe);
Rti tArg = _castToRti(_Utils.arrayAt(tArgs, i));
- if (!_isSubtype(universe, supertypeArg, sEnv, tArg, tEnv)) return false;
+ if (!_isSubtype(universe, supertypeArg, sEnv, tArg, tEnv, isLegacy)) {
+ return false;
+ }
}
return true;
}
@@ -2620,10 +2675,10 @@
///
/// We ignore renaming of bound type variables because we operate on de Bruijn
/// indices, not names.
-bool typeEqual(Rti s, Rti t) {
+bool typeEqual(Rti s, Rti t, bool isLegacy) {
if (_Utils.isIdentical(s, t)) return true;
- if (isTopType(s)) return isTopType(t);
+ if (isTopType(s, isLegacy)) return isTopType(t, isLegacy);
int sKind = Rti._getKind(s);
int tKind = Rti._getKind(t);
@@ -2633,46 +2688,49 @@
case Rti.kindStar:
case Rti.kindQuestion:
case Rti.kindFutureOr:
- return typeEqual(
- _castToRti(Rti._getPrimary(s)), _castToRti(Rti._getPrimary(t)));
+ return typeEqual(_castToRti(Rti._getPrimary(s)),
+ _castToRti(Rti._getPrimary(t)), isLegacy);
case Rti.kindInterface:
if (Rti._getInterfaceName(s) != Rti._getInterfaceName(t)) return false;
- return typesEqual(
- Rti._getInterfaceTypeArguments(s), Rti._getInterfaceTypeArguments(t));
+ return typesEqual(Rti._getInterfaceTypeArguments(s),
+ Rti._getInterfaceTypeArguments(t), isLegacy);
case Rti.kindBinding:
- return typeEqual(Rti._getBindingBase(s), Rti._getBindingBase(t)) &&
- typesEqual(Rti._getBindingArguments(s), Rti._getBindingArguments(t));
+ return typeEqual(
+ Rti._getBindingBase(s), Rti._getBindingBase(t), isLegacy) &&
+ typesEqual(Rti._getBindingArguments(s), Rti._getBindingArguments(t),
+ isLegacy);
case Rti.kindFunction:
- return typeEqual(Rti._getReturnType(s), Rti._getReturnType(t)) &&
- functionParametersEqual(
- Rti._getFunctionParameters(s), Rti._getFunctionParameters(t));
+ return typeEqual(
+ Rti._getReturnType(s), Rti._getReturnType(t), isLegacy) &&
+ functionParametersEqual(Rti._getFunctionParameters(s),
+ Rti._getFunctionParameters(t), isLegacy);
case Rti.kindGenericFunction:
- return typeEqual(
- Rti._getGenericFunctionBase(s), Rti._getGenericFunctionBase(t)) &&
+ return typeEqual(Rti._getGenericFunctionBase(s),
+ Rti._getGenericFunctionBase(t), isLegacy) &&
typesEqual(Rti._getGenericFunctionBounds(s),
- Rti._getGenericFunctionBounds(t));
+ Rti._getGenericFunctionBounds(t), isLegacy);
default:
return false;
}
}
-bool typesEqual(Object sArray, Object tArray) {
+bool typesEqual(Object sArray, Object tArray, isLegacy) {
int sLength = _Utils.arrayLength(sArray);
int tLength = _Utils.arrayLength(tArray);
if (sLength != tLength) return false;
for (int i = 0; i < sLength; i++) {
if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i)),
- _castToRti(_Utils.arrayAt(tArray, i)))) return false;
+ _castToRti(_Utils.arrayAt(tArray, i)), isLegacy)) return false;
}
return true;
}
-bool namedTypesEqual(Object sArray, Object tArray) {
+bool namedTypesEqual(Object sArray, Object tArray, isLegacy) {
int sLength = _Utils.arrayLength(sArray);
int tLength = _Utils.arrayLength(tArray);
assert(sLength.isEven);
@@ -2682,34 +2740,43 @@
if (_Utils.asString(_Utils.arrayAt(sArray, i)) !=
_Utils.asString(_Utils.arrayAt(tArray, i))) return false;
if (!typeEqual(_castToRti(_Utils.arrayAt(sArray, i + 1)),
- _castToRti(_Utils.arrayAt(tArray, i + 1)))) return false;
+ _castToRti(_Utils.arrayAt(tArray, i + 1)), isLegacy)) return false;
}
return true;
}
// TODO(fishythefish): Support required named parameters.
-bool functionParametersEqual(
- _FunctionParameters sParameters, _FunctionParameters tParameters) =>
+bool functionParametersEqual(_FunctionParameters sParameters,
+ _FunctionParameters tParameters, isLegacy) =>
typesEqual(_FunctionParameters._getRequiredPositional(sParameters),
- _FunctionParameters._getRequiredPositional(tParameters)) &&
+ _FunctionParameters._getRequiredPositional(tParameters), isLegacy) &&
typesEqual(_FunctionParameters._getOptionalPositional(sParameters),
- _FunctionParameters._getOptionalPositional(tParameters)) &&
+ _FunctionParameters._getOptionalPositional(tParameters), isLegacy) &&
namedTypesEqual(_FunctionParameters._getOptionalNamed(sParameters),
- _FunctionParameters._getOptionalNamed(tParameters));
+ _FunctionParameters._getOptionalNamed(tParameters), isLegacy);
-// TODO(fishythefish): Update for NNBD - check for `Object?` instead of
-// `Object`.
-bool isTopType(Rti t) {
- if (isObjectType(t)) return true;
+bool isLegacyTopType(Rti t) => isTopType(t, true);
+bool isNnbdTopType(Rti t) => isTopType(t, false);
+bool isTopType(Rti t, bool isLegacy) {
+ if (isLegacy) {
+ if (isObjectType(t)) return true;
+ } else {
+ if (isNullableObjectType(t)) return true;
+ }
int kind = Rti._getKind(t);
return kind == Rti.kindDynamic ||
kind == Rti.kindVoid ||
kind == Rti.kindAny ||
kind == Rti.kindErased ||
- kind == Rti.kindFutureOr && isTopType(Rti._getFutureOrArgument(t));
+ kind == Rti.kindFutureOr &&
+ isTopType(Rti._getFutureOrArgument(t), isLegacy);
}
bool isObjectType(Rti t) => _Utils.isIdentical(t, TYPE_REF<Object>());
+// TODO(fishythefish): Use `TYPE_REF<Object?>()`.
+bool isNullableObjectType(Rti t) =>
+ Rti._getKind(t) == Rti.kindQuestion &&
+ isObjectType(Rti._getQuestionArgument(t));
bool isNullType(Rti t) => _Utils.isIdentical(t, TYPE_REF<Null>());
bool isFunctionType(Rti t) => _Utils.isIdentical(t, TYPE_REF<Function>());
bool isJsFunctionType(Rti t) =>
@@ -2808,8 +2875,8 @@
_Universe.addTypeParameterVariances(universe, variances);
}
-bool testingIsSubtype(universe, rti1, rti2) {
- return isSubtype(universe, _castToRti(rti1), _castToRti(rti2));
+bool testingIsLegacySubtype(universe, rti1, rti2) {
+ return isLegacySubtype(universe, _castToRti(rti1), _castToRti(rti2));
}
Object testingUniverseEval(universe, String recipe) {
diff --git a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
index 523a0c1..b8e584b 100644
--- a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -91,10 +91,11 @@
categories: "Client,Server",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
- "js": const LibraryInfo("js/dart2js/js_dart2js.dart",
+ "js": const LibraryInfo("js/js.dart",
categories: "Client",
maturity: Maturity.STABLE,
- platforms: DART2JS_PLATFORM),
+ platforms: DART2JS_PLATFORM,
+ dart2jsPatchPath: "_internal/js_runtime/lib/js_patch.dart"),
"_js": const LibraryInfo("js/_js.dart",
categories: "Client",
dart2jsPatchPath: "js/_js_client.dart",
diff --git a/sdk_nnbd/lib/async/stream_controller.dart b/sdk_nnbd/lib/async/stream_controller.dart
index 7861fb8..31fc5c3 100644
--- a/sdk_nnbd/lib/async/stream_controller.dart
+++ b/sdk_nnbd/lib/async/stream_controller.dart
@@ -515,7 +515,7 @@
_PendingEvents<T>? get _pendingEvents {
assert(_isInitialState);
if (!_isAddingStream) {
- return _varData;
+ return _varData as _PendingEvents<T>?;
}
var state = _varData as _StreamControllerAddStreamState<T>;
return state.varData;
@@ -679,7 +679,7 @@
_ControllerSubscription<T> subscription = _ControllerSubscription<T>(
this, onData, onError, onDone, cancelOnError);
- _PendingEvents<T> pendingEvents = _pendingEvents;
+ _PendingEvents<T>? pendingEvents = _pendingEvents;
_state |= _STATE_SUBSCRIBED;
if (_isAddingStream) {
var addState = _varData as _StreamControllerAddStreamState<T>;
diff --git a/sdk_nnbd/lib/async/zone.dart b/sdk_nnbd/lib/async/zone.dart
index 8be575d1..31644f2 100644
--- a/sdk_nnbd/lib/async/zone.dart
+++ b/sdk_nnbd/lib/async/zone.dart
@@ -110,16 +110,14 @@
ForkHandler? fork}) {
return new ZoneSpecification(
handleUncaughtError: handleUncaughtError ?? other.handleUncaughtError,
- // TODO(#39534) Cleanup casts to dynamic when CFE can find the LUB.
- run: (run ?? other.run) as dynamic,
- runUnary: (runUnary ?? other.runUnary) as dynamic,
- runBinary: (runBinary ?? other.runBinary) as dynamic,
- registerCallback:
- (registerCallback ?? other.registerCallback) as dynamic,
+ run: run ?? other.run,
+ runUnary: runUnary ?? other.runUnary,
+ runBinary: runBinary ?? other.runBinary,
+ registerCallback: registerCallback ?? other.registerCallback,
registerUnaryCallback:
- (registerUnaryCallback ?? other.registerUnaryCallback) as dynamic,
+ registerUnaryCallback ?? other.registerUnaryCallback,
registerBinaryCallback:
- (registerBinaryCallback ?? other.registerBinaryCallback) as dynamic,
+ registerBinaryCallback ?? other.registerBinaryCallback,
errorCallback: errorCallback ?? other.errorCallback,
scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
createTimer: createTimer ?? other.createTimer,
diff --git a/sdk_nnbd/lib/js/js.dart b/sdk_nnbd/lib/js/js.dart
new file mode 100644
index 0000000..139823d
--- /dev/null
+++ b/sdk_nnbd/lib/js/js.dart
@@ -0,0 +1,235 @@
+// Copyright (c) 2013, 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.6
+
+/// Low-level support for interoperating with JavaScript.
+///
+/// You should usually use `package:js` instead of this library. For more
+/// information, see the [JS interop page](https://dart.dev/web/js-interop).
+///
+/// This library provides access to JavaScript objects from Dart, allowing
+/// Dart code to get and set properties, and call methods of JavaScript objects
+/// and invoke JavaScript functions. The library takes care of converting
+/// between Dart and JavaScript objects where possible, or providing proxies if
+/// conversion isn't possible.
+///
+/// This library does not make Dart objects usable from JavaScript, their
+/// methods and properties are not accessible, though it does allow Dart
+/// functions to be passed into and called from JavaScript.
+///
+/// [JsObject] is the core type and represents a proxy of a JavaScript object.
+/// JsObject gives access to the underlying JavaScript objects properties and
+/// methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
+/// created from proxies to JavaScript constructors.
+///
+/// The top-level getter [context] provides a [JsObject] that represents the
+/// global object in JavaScript, usually `window`.
+///
+/// The following example shows an alert dialog via a JavaScript call to the
+/// global function `alert()`:
+///
+/// import 'dart:js';
+///
+/// main() => context.callMethod('alert', ['Hello from Dart!']);
+///
+/// This example shows how to create a [JsObject] from a JavaScript constructor
+/// and access its properties:
+///
+/// import 'dart:js';
+///
+/// main() {
+/// var object = JsObject(context['Object']);
+/// object['greeting'] = 'Hello';
+/// object['greet'] = (name) => "${object['greeting']} $name";
+/// var message = object.callMethod('greet', ['JavaScript']);
+/// context['console'].callMethod('log', [message]);
+/// }
+///
+/// ## Proxying and automatic conversion
+///
+/// When setting properties on a JsObject or passing arguments to a Javascript
+/// method or function, Dart objects are automatically converted or proxied to
+/// JavaScript objects. When accessing JavaScript properties, or when a Dart
+/// closure is invoked from JavaScript, the JavaScript objects are also
+/// converted to Dart.
+///
+/// Functions and closures are proxied in such a way that they are callable. A
+/// Dart closure assigned to a JavaScript property is proxied by a function in
+/// JavaScript. A JavaScript function accessed from Dart is proxied by a
+/// [JsFunction], which has a [JsFunction.apply] method to invoke it.
+///
+/// The following types are transferred directly and not proxied:
+///
+/// * Basic types: `null`, `bool`, `num`, `String`, `DateTime`
+/// * `TypedData`, including its subclasses like `Int32List`, but _not_
+/// `ByteBuffer`
+/// * When compiling for the web, also: `Blob`, `Event`, `ImageData`,
+/// `KeyRange`, `Node`, and `Window`.
+///
+/// ## Converting collections with JsObject.jsify()
+///
+/// To create a JavaScript collection from a Dart collection use the
+/// [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
+/// into JavaScript Objects and Arrays.
+///
+/// The following expression creates a new JavaScript object with the properties
+/// `a` and `b` defined:
+///
+/// var jsMap = JsObject.jsify({'a': 1, 'b': 2});
+///
+/// This expression creates a JavaScript array:
+///
+/// var jsArray = JsObject.jsify([1, 2, 3]);
+///
+/// {@category Web}
+library dart.js;
+
+import 'dart:collection' show ListMixin;
+
+/// The JavaScript global object, usually `window`.
+external JsObject get context;
+
+/// A proxy on a JavaScript object.
+///
+/// The properties of the JavaScript object are accessible via the `[]` and
+/// `[]=` operators. Methods are callable via [callMethod].
+class JsObject {
+ /// Constructs a JavaScript object from its native [constructor] and returns
+ /// a proxy to it.
+ external factory JsObject(JsFunction constructor, [List arguments]);
+
+ /// Constructs a [JsObject] that proxies a native Dart object; _for expert use
+ /// only_.
+ ///
+ /// Use this constructor only if you wish to get access to JavaScript
+ /// properties attached to a browser host object, such as a Node or Blob, that
+ /// is normally automatically converted into a native Dart object.
+ ///
+ /// An exception will be thrown if [object] either is `null` or has the type
+ /// `bool`, `num`, or `String`.
+ external factory JsObject.fromBrowserObject(object);
+
+ /// Recursively converts a JSON-like collection of Dart objects to a
+ /// collection of JavaScript objects and returns a [JsObject] proxy to it.
+ ///
+ /// [object] must be a [Map] or [Iterable], the contents of which are also
+ /// converted. Maps and Iterables are copied to a new JavaScript object.
+ /// Primitives and other transferable values are directly converted to their
+ /// JavaScript type, and all other objects are proxied.
+ external factory JsObject.jsify(object);
+
+ /// Returns the value associated with [property] from the proxied JavaScript
+ /// object.
+ ///
+ /// The type of [property] must be either [String] or [num].
+ external dynamic operator [](property);
+
+ // Sets the value associated with [property] on the proxied JavaScript
+ // object.
+ //
+ // The type of [property] must be either [String] or [num].
+ external void operator []=(property, value);
+
+ int get hashCode => 0;
+
+ external bool operator ==(other);
+
+ /// Returns `true` if the JavaScript object contains the specified property
+ /// either directly or though its prototype chain.
+ ///
+ /// This is the equivalent of the `in` operator in JavaScript.
+ external bool hasProperty(property);
+
+ /// Removes [property] from the JavaScript object.
+ ///
+ /// This is the equivalent of the `delete` operator in JavaScript.
+ external void deleteProperty(property);
+
+ /// Returns `true` if the JavaScript object has [type] in its prototype chain.
+ ///
+ /// This is the equivalent of the `instanceof` operator in JavaScript.
+ external bool instanceof(JsFunction type);
+
+ /// Returns the result of the JavaScript objects `toString` method.
+ external String toString();
+
+ /// Calls [method] on the JavaScript object with the arguments [args] and
+ /// returns the result.
+ ///
+ /// The type of [method] must be either [String] or [num].
+ external dynamic callMethod(method, [List args]);
+}
+
+/// A proxy on a JavaScript Function object.
+class JsFunction extends JsObject {
+ /// Returns a [JsFunction] that captures its 'this' binding and calls [f]
+ /// with the value of JavaScript `this` passed as the first argument.
+ external factory JsFunction.withThis(Function f);
+
+ /// Invokes the JavaScript function with arguments [args]. If [thisArg] is
+ /// supplied it is the value of `this` for the invocation.
+ external dynamic apply(List args, {thisArg});
+}
+
+/// A [List] that proxies a JavaScript array.
+class JsArray<E> extends JsObject with ListMixin<E> {
+ /// Creates an empty JavaScript array.
+ external factory JsArray();
+
+ /// Creates a new JavaScript array and initializes it to the contents of
+ /// [other].
+ external factory JsArray.from(Iterable<E> other);
+
+ // Methods required by ListMixin
+
+ external E operator [](dynamic index);
+
+ external void operator []=(dynamic index, E value);
+
+ external int get length;
+
+ external void set length(int length);
+
+ // Methods overridden for better performance
+
+ external void add(E value);
+
+ external void addAll(Iterable<E> iterable);
+
+ external void insert(int index, E element);
+
+ external E removeAt(int index);
+
+ external E removeLast();
+
+ external void removeRange(int start, int end);
+
+ external void setRange(int start, int end, Iterable<E> iterable,
+ [int skipCount = 0]);
+
+ external void sort([int compare(E a, E b)]);
+}
+
+/// Returns a wrapper around function [f] that can be called from JavaScript
+/// using `package:js` JavaScript interop.
+///
+/// The calling conventions in Dart2Js differ from JavaScript and so, by
+/// default, it is not possible to call a Dart function directly. Wrapping with
+/// `allowInterop` creates a function that can be called from JavaScript or
+/// Dart. The semantics of the wrapped function are still more strict than
+/// JavaScript, and the function will throw if called with too many or too few
+/// arguments.
+///
+/// Calling this method repeatedly on a function will return the same result.
+external F allowInterop<F extends Function>(F f);
+
+/// Returns a wrapper around function [f] that can be called from JavaScript
+/// using `package:js` JavaScript interop, passing JavaScript `this` as the first
+/// argument.
+///
+/// See [allowInterop].
+///
+/// When called from Dart, [null] will be passed as the first argument.
+external Function allowInteropCaptureThis(Function f);
diff --git a/sdk_nnbd/lib/js/js_sources.gni b/sdk_nnbd/lib/js/js_sources.gni
index 91f6d0c..6308b38 100644
--- a/sdk_nnbd/lib/js/js_sources.gni
+++ b/sdk_nnbd/lib/js/js_sources.gni
@@ -2,4 +2,4 @@
# 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.
-js_sdk_sources = [ "dart2js/js_dart2js.dart" ]
+js_sdk_sources = [ "js.dart" ]
diff --git a/sdk_nnbd/lib/libraries.json b/sdk_nnbd/lib/libraries.json
index e8107ef..3391292 100644
--- a/sdk_nnbd/lib/libraries.json
+++ b/sdk_nnbd/lib/libraries.json
@@ -203,7 +203,8 @@
"supported": false
},
"js": {
- "uri": "../../sdk/lib/js/dart2js/js_dart2js.dart"
+ "uri": "../../sdk/lib/js/js.dart",
+ "patches": "../../sdk/lib/_internal/js_runtime/lib/js_patch.dart"
},
"_js": {
"uri": "../../sdk/lib/js/_js.dart",
@@ -312,7 +313,8 @@
"supported": false
},
"js": {
- "uri": "../../sdk/lib/js/dart2js/js_dart2js.dart"
+ "uri": "../../sdk/lib/js/js.dart",
+ "patches": "../../sdk/lib/_internal/js_runtime/lib/js_patch.dart"
},
"_js": {
"uri": "../../sdk/lib/js/_js.dart",
@@ -462,7 +464,8 @@
"uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
},
"js": {
- "uri": "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+ "uri": "js/js.dart",
+ "patches": "_internal/js_dev_runtime/patch/js_patch.dart"
},
"js_util": {
"uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
diff --git a/sdk_nnbd/lib/libraries.yaml b/sdk_nnbd/lib/libraries.yaml
index 6fbbdff..1aa29b8 100644
--- a/sdk_nnbd/lib/libraries.yaml
+++ b/sdk_nnbd/lib/libraries.yaml
@@ -200,7 +200,8 @@
supported: false
js:
- uri: "../../sdk/lib/js/dart2js/js_dart2js.dart"
+ uri: "../../sdk/lib/js/js.dart"
+ patches: "../../sdk/lib/_internal/js_runtime/lib/js_patch.dart"
_js:
uri: "../../sdk/lib/js/_js.dart"
@@ -307,7 +308,8 @@
supported: false
js:
- uri: "../../sdk/lib/js/dart2js/js_dart2js.dart"
+ uri: "../../sdk/lib/js/js.dart"
+ patches: "../../sdk/lib/_internal/js_runtime/lib/js_patch.dart"
_js:
uri: "../../sdk/lib/js/_js.dart"
@@ -455,7 +457,8 @@
uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
js:
- uri: "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+ uri: "js/js.dart"
+ patches: "_internal/js_dev_runtime/patch/js_patch.dart"
js_util:
uri: "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
diff --git a/tests/compiler/dart2js/analyses/api_allowed.json b/tests/compiler/dart2js/analyses/api_allowed.json
index b988fc0..062db80 100644
--- a/tests/compiler/dart2js/analyses/api_allowed.json
+++ b/tests/compiler/dart2js/analyses/api_allowed.json
@@ -169,7 +169,7 @@
"org-dartlang-sdk:///sdk/lib/io/common.dart": {
"Dynamic invocation of '[]'.": 3
},
- "org-dartlang-sdk:///sdk/lib/js/dart2js/js_dart2js.dart": {
+ "org-dartlang-sdk:///sdk/lib/_internal/js_runtime/lib/js_patch.dart": {
"Dynamic invocation of '[]'.": 1
},
"org-dartlang-sdk:///sdk/lib/svg/dart2js/svg_dart2js.dart": {
@@ -225,4 +225,4 @@
"Dynamic access of 'port'.": 1,
"Dynamic invocation of 'dart._http::_toJSON'.": 1
}
-}
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/inference/data/closurization_instance_call.dart b/tests/compiler/dart2js/inference/data/closurization_instance_call.dart
index 4f785bf..d5eabac 100644
--- a/tests/compiler/dart2js/inference/data/closurization_instance_call.dart
+++ b/tests/compiler/dart2js/inference/data/closurization_instance_call.dart
@@ -24,7 +24,7 @@
/*member: closurizedCallToString:[exact=JSString]*/
closurizedCallToString() {
var c = new Class();
- c.call(); // Make `Class.call` live.
+ c. /*invoke: [null|exact=Class]*/ call(); // Make `Class.call` live.
var local = c. /*[exact=Class]*/ method;
local. /*invoke: [subclass=Closure]*/ toString();
local();
diff --git a/tests/compiler/dart2js/inference/data/closurization_local_call.dart b/tests/compiler/dart2js/inference/data/closurization_local_call.dart
index 65439e1..19c5758 100644
--- a/tests/compiler/dart2js/inference/data/closurization_local_call.dart
+++ b/tests/compiler/dart2js/inference/data/closurization_local_call.dart
@@ -21,7 +21,7 @@
/*member: closurizedCallToString:[exact=JSString]*/
closurizedCallToString() {
var c = new Class();
- c.call(); // Make `Class.call` live.
+ c. /*invoke: [null|exact=Class]*/ call(); // Make `Class.call` live.
var local = /*[exact=JSUInt31]*/ () => 42;
local. /*invoke: [subclass=Closure]*/ toString();
local();
diff --git a/tests/compiler/dart2js/inference/data/closurization_static_call.dart b/tests/compiler/dart2js/inference/data/closurization_static_call.dart
index a29e594..575f68d 100644
--- a/tests/compiler/dart2js/inference/data/closurization_static_call.dart
+++ b/tests/compiler/dart2js/inference/data/closurization_static_call.dart
@@ -24,7 +24,7 @@
/*member: closurizedCallToString:[exact=JSString]*/
closurizedCallToString() {
var c = new Class();
- c.call(); // Make `Class.call` live.
+ c. /*invoke: [null|exact=Class]*/ call(); // Make `Class.call` live.
var local = method;
local. /*invoke: [subclass=Closure]*/ toString();
local();
diff --git a/tests/compiler/dart2js/inference/data/do.dart b/tests/compiler/dart2js/inference/data/do.dart
index f900e4b..5a7ffac 100644
--- a/tests/compiler/dart2js/inference/data/do.dart
+++ b/tests/compiler/dart2js/inference/data/do.dart
@@ -47,7 +47,7 @@
var o = '';
do {
o = o. /*invoke: [exact=JSString]*/ toString();
- } while (o != null);
+ } while (o /*invoke: [null|exact=JSString]*/ != null);
return o;
}
@@ -60,7 +60,7 @@
var o = '';
do {
o = o. /*invoke: [exact=JSString]*/ toString();
- } while (o == null);
+ } while (o /*invoke: [null|exact=JSString]*/ == null);
return o;
}
diff --git a/tests/compiler/dart2js/inference/data/for.dart b/tests/compiler/dart2js/inference/data/for.dart
index 72cc8bb..5af242e 100644
--- a/tests/compiler/dart2js/inference/data/for.dart
+++ b/tests/compiler/dart2js/inference/data/for.dart
@@ -47,7 +47,9 @@
/*member: forNotNull:[null|exact=JSString]*/
forNotNull() {
var local;
- for (var o = ''; o != null; o = o. /*invoke: [exact=JSString]*/ toString()) {
+ for (var o = '';
+ o /*invoke: [null|exact=JSString]*/ != null;
+ o = o. /*invoke: [exact=JSString]*/ toString()) {
local = o;
}
return local;
@@ -60,7 +62,9 @@
/*member: forNullFalse:[null]*/
forNullFalse() {
var local;
- for (var o = ''; o == null; o = o. /*invoke: [null]*/ toString()) {
+ for (var o = '';
+ o /*invoke: [null|exact=JSString]*/ == null;
+ o = o. /*invoke: [null]*/ toString()) {
local = o;
}
return local;
diff --git a/tests/compiler/dart2js/inference/data/general.dart b/tests/compiler/dart2js/inference/data/general.dart
index b73d97f..f858024 100644
--- a/tests/compiler/dart2js/inference/data/general.dart
+++ b/tests/compiler/dart2js/inference/data/general.dart
@@ -675,7 +675,8 @@
A.generative();
/*member: A.==:[exact=JSBool]*/
- operator ==(/*[null|subclass=Object]*/ other) => 42 as dynamic;
+ operator ==(/*Union([exact=JSString], [exact=JSUInt31])*/ other) =>
+ 42 as dynamic;
/*member: A.myField:[exact=JSUInt31]*/
get myField => 42;
@@ -892,7 +893,7 @@
testDoWhile2();
testDoWhile3();
testDoWhile4();
- new A() == null;
+ new A() /*invoke: [null|subclass=A]*/ == null;
new A()
.. /*invoke: [exact=A]*/ returnInt1()
.. /*invoke: [exact=A]*/ returnInt2()
diff --git a/tests/compiler/dart2js/inference/data/narrowing.dart b/tests/compiler/dart2js/inference/data/narrowing.dart
index ba26c79..27c041d 100644
--- a/tests/compiler/dart2js/inference/data/narrowing.dart
+++ b/tests/compiler/dart2js/inference/data/narrowing.dart
@@ -13,7 +13,7 @@
/*member: nonNull1:[null]*/
void nonNull1() {
var x = 1;
- if (x == null) return;
+ if (x /*invoke: [null|subclass=JSInt]*/ == null) return;
argIsNonNull1(x);
}
@@ -25,7 +25,9 @@
/*member: nonNull2:[null]*/
void nonNull2() {
var x = 1;
- if ((x == null) /*invoke: [exact=JSBool]*/ == true) return;
+ if ((x /*invoke: [null|subclass=JSInt]*/ ==
+ null) /*invoke: [exact=JSBool]*/ ==
+ true) return;
argIsNonNull2(x);
}
@@ -37,7 +39,9 @@
/*member: nonNull3:[null]*/
void nonNull3() {
var x = 1;
- if ((x == null) /*invoke: [exact=JSBool]*/ != false) return;
+ if ((x /*invoke: [null|subclass=JSInt]*/ ==
+ null) /*invoke: [exact=JSBool]*/ !=
+ false) return;
argIsNonNull3(x);
}
@@ -52,7 +56,7 @@
/*member: nonNull4:[null]*/
void nonNull4() {
var x = 1;
- if (discard(x != null)) return;
+ if (discard(x /*invoke: [null|subclass=JSInt]*/ != null)) return;
argIsNonNull4(x);
}
@@ -64,7 +68,7 @@
/*member: nonNull5:[null]*/
void nonNull5() {
var x = 1;
- if (x != null ? false : false) return;
+ if (x /*invoke: [null|subclass=JSInt]*/ != null ? false : false) return;
argIsNonNull5(x);
}
@@ -76,8 +80,8 @@
/*member: nonNull6:[null]*/
void nonNull6() {
var x = 1;
- if ((/*[exact=JSBool]*/ (/*[exact=JSBool]*/ y) => y && false)(x != null))
- return;
+ if ((/*[exact=JSBool]*/ (/*[exact=JSBool]*/ y) =>
+ y && false)(x /*invoke: [null|subclass=JSInt]*/ != null)) return;
argIsNonNull6(x);
}
@@ -90,7 +94,7 @@
void nonNull7() {
var f = false;
var x = 1;
- if (f ? (throw x != null) : false) return;
+ if (f ? (throw x /*invoke: [null|subclass=JSInt]*/ != null) : false) return;
argIsNonNull7(x);
}
@@ -103,7 +107,7 @@
void nonNull8() {
var f = false;
var x = 1;
- if (f ?? (x != null)) return;
+ if (f ?? (x /*invoke: [null|subclass=JSInt]*/ != null)) return;
argIsNonNull8(x);
}
diff --git a/tests/compiler/dart2js/inference/data/null.dart b/tests/compiler/dart2js/inference/data/null.dart
index 9e53378..05fd76b 100644
--- a/tests/compiler/dart2js/inference/data/null.dart
+++ b/tests/compiler/dart2js/inference/data/null.dart
@@ -24,7 +24,7 @@
/*member: ifThenNullCheck:[exact=JSUInt31]*/
ifThenNullCheck(int /*[null|exact=JSUInt31]*/ value) {
- if (value == null) {
+ if (value /*invoke: [null|subclass=JSInt]*/ == null) {
return 0;
}
return value;
@@ -32,7 +32,7 @@
/*member: ifThenElseNullCheck:[exact=JSUInt31]*/
ifThenElseNullCheck(int /*[null|exact=JSUInt31]*/ value) {
- if (value == null) {
+ if (value /*invoke: [null|subclass=JSInt]*/ == null) {
return 0;
} else {
return value;
@@ -41,7 +41,7 @@
/*member: ifNotThenNullCheck:[exact=JSUInt31]*/
ifNotThenNullCheck(int /*[null|exact=JSUInt31]*/ value) {
- if (value != null) {
+ if (value /*invoke: [null|subclass=JSInt]*/ != null) {
return value;
}
return 0;
@@ -49,7 +49,7 @@
/*member: ifNotThenElseNullCheck:[exact=JSUInt31]*/
ifNotThenElseNullCheck(int /*[null|exact=JSUInt31]*/ value) {
- if (value != null) {
+ if (value /*invoke: [null|subclass=JSInt]*/ != null) {
return value;
} else {
return 0;
@@ -59,7 +59,8 @@
/*member: ifThenNotNullComplexCheck:[exact=JSUInt31]*/
ifThenNotNullComplexCheck(
int /*[null|exact=JSUInt31]*/ a, int /*[null|exact=JSUInt31]*/ b) {
- if (a != null && a /*invoke: [exact=JSUInt31]*/ != b) {
+ if (a /*invoke: [null|subclass=JSInt]*/ != null &&
+ a /*invoke: [exact=JSUInt31]*/ != b) {
return a;
}
return 0;
@@ -68,7 +69,8 @@
/*member: ifThenElseNotNullComplexCheck:[null|exact=JSUInt31]*/
ifThenElseNotNullComplexCheck(
int /*[null|exact=JSUInt31]*/ a, int /*[null|exact=JSUInt31]*/ b) {
- if (a != null && a /*invoke: [exact=JSUInt31]*/ != b) {
+ if (a /*invoke: [null|subclass=JSInt]*/ != null &&
+ a /*invoke: [exact=JSUInt31]*/ != b) {
return a;
}
return a;
@@ -78,7 +80,7 @@
ifThenNotNullGradualCheck1(
int /*[null|exact=JSUInt31]*/ a, int /*[exact=JSUInt31]*/ b) {
if (a /*invoke: [null|exact=JSUInt31]*/ != b) {
- if (a != null) {
+ if (a /*invoke: [null|subclass=JSInt]*/ != null) {
return a;
}
}
@@ -88,7 +90,7 @@
/*member: ifThenNotNullGradualCheck2:[exact=JSUInt31]*/
ifThenNotNullGradualCheck2(
int /*[null|exact=JSUInt31]*/ a, int /*[exact=JSUInt31]*/ b) {
- if (a != null) {
+ if (a /*invoke: [null|subclass=JSInt]*/ != null) {
if (a /*invoke: [exact=JSUInt31]*/ != b) {
return a;
}
diff --git a/tests/compiler/dart2js/inference/data/while.dart b/tests/compiler/dart2js/inference/data/while.dart
index 4a711e2..73b214e 100644
--- a/tests/compiler/dart2js/inference/data/while.dart
+++ b/tests/compiler/dart2js/inference/data/while.dart
@@ -49,7 +49,7 @@
/*member: whileNotNull:[exact=JSString]*/
whileNotNull() {
var o = '';
- while (o != null) {
+ while (o /*invoke: [null|exact=JSString]*/ != null) {
o = o. /*invoke: [exact=JSString]*/ toString();
}
return o;
@@ -62,7 +62,7 @@
/*member: whileNullUnreachable:[exact=JSString]*/
whileNullUnreachable() {
var o = '';
- while (o == null) {
+ while (o /*invoke: [null|exact=JSString]*/ == null) {
o = o. /*invoke: [null]*/ toString();
}
return o;
diff --git a/tests/compiler/dart2js/inference/inference_data/called_in_loop.dart b/tests/compiler/dart2js/inference/inference_data/called_in_loop.dart
index d984418..884773e 100644
--- a/tests/compiler/dart2js/inference/inference_data/called_in_loop.dart
+++ b/tests/compiler/dart2js/inference/inference_data/called_in_loop.dart
@@ -84,7 +84,7 @@
Class.constructorNotCalledInForLoop();
// TODO(johnniwinther): Should we track instance calls in loops?
- /*member: Class.instanceCalledInForLoop:*/
+ /*member: Class.instanceCalledInForLoop:loop*/
instanceCalledInForLoop() {}
/*member: Class.instanceNotCalledInForLoop:*/
diff --git a/tests/compiler/dart2js/inference/inference_data_test.dart b/tests/compiler/dart2js/inference/inference_data_test.dart
index e89e33e..c9aad1d 100644
--- a/tests/compiler/dart2js/inference/inference_data_test.dart
+++ b/tests/compiler/dart2js/inference/inference_data_test.dart
@@ -24,6 +24,7 @@
await checkTests(dataDir, const InferenceDataComputer(),
args: args,
testedConfigs: [strongConfig],
+ supportedMarkers: [strongMarker],
options: [stopAfterTypeInference]);
});
}
diff --git a/tests/compiler/dart2js/inference/inference_test_helper.dart b/tests/compiler/dart2js/inference/inference_test_helper.dart
index 06da02c..d0b6caa 100644
--- a/tests/compiler/dart2js/inference/inference_test_helper.dart
+++ b/tests/compiler/dart2js/inference/inference_test_helper.dart
@@ -146,11 +146,11 @@
ClosureRepresentationInfo info = _closureDataLookup.getClosureInfo(node);
return getMemberValue(info.callMethod);
} else if (node is ir.MethodInvocation) {
- return getTypeMaskValue(result.typeOfSend(node));
+ return getTypeMaskValue(result.typeOfReceiver(node));
} else if (node is ir.PropertyGet) {
- return getTypeMaskValue(result.typeOfGetter(node));
+ return getTypeMaskValue(result.typeOfReceiver(node));
} else if (node is ir.PropertySet) {
- return getTypeMaskValue(result.typeOfSend(node));
+ return getTypeMaskValue(result.typeOfReceiver(node));
} else if (node is ir.ForInStatement) {
if (id.kind == IdKind.iterator) {
return getTypeMaskValue(result.typeOfIterator(node));
diff --git a/tests/compiler/dart2js_extra/rti/subtype_utils.dart b/tests/compiler/dart2js_extra/rti/subtype_utils.dart
index dc4f608..f147dc7 100644
--- a/tests/compiler/dart2js_extra/rti/subtype_utils.dart
+++ b/tests/compiler/dart2js_extra/rti/subtype_utils.dart
@@ -12,20 +12,23 @@
void strictSubtype(String s, String t) {
var sRti = rti.testingUniverseEval(universe, s);
var tRti = rti.testingUniverseEval(universe, t);
- Expect.isTrue(rti.testingIsSubtype(universe, sRti, tRti), reason(s, t));
- Expect.isFalse(rti.testingIsSubtype(universe, tRti, sRti), reason(t, s));
+ Expect.isTrue(rti.testingIsLegacySubtype(universe, sRti, tRti), reason(s, t));
+ Expect.isFalse(
+ rti.testingIsLegacySubtype(universe, tRti, sRti), reason(t, s));
}
void unrelated(String s, String t) {
var sRti = rti.testingUniverseEval(universe, s);
var tRti = rti.testingUniverseEval(universe, t);
- Expect.isFalse(rti.testingIsSubtype(universe, sRti, tRti), reason(s, t));
- Expect.isFalse(rti.testingIsSubtype(universe, tRti, sRti), reason(t, s));
+ Expect.isFalse(
+ rti.testingIsLegacySubtype(universe, sRti, tRti), reason(s, t));
+ Expect.isFalse(
+ rti.testingIsLegacySubtype(universe, tRti, sRti), reason(t, s));
}
void equivalent(String s, String t) {
var sRti = rti.testingUniverseEval(universe, s);
var tRti = rti.testingUniverseEval(universe, t);
- Expect.isTrue(rti.testingIsSubtype(universe, sRti, tRti), reason(s, t));
- Expect.isTrue(rti.testingIsSubtype(universe, tRti, sRti), reason(t, s));
+ Expect.isTrue(rti.testingIsLegacySubtype(universe, sRti, tRti), reason(s, t));
+ Expect.isTrue(rti.testingIsLegacySubtype(universe, tRti, sRti), reason(t, s));
}
diff --git a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
index 297cfcd..04d90b6 100644
--- a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
@@ -53,7 +53,7 @@
// The instance getter shadows the global method
topLevelMethod(4);
// ^^^^^^^^^^^^^^
-// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^
// [cfe] The method 'call' isn't defined for the class 'int'.
}
@@ -145,7 +145,7 @@
// The static getter shadows the global method
topLevelMethod(4);
// ^^^^^^^^^^^^^^
-// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^
// [cfe] The method 'call' isn't defined for the class 'int'.
}
@@ -227,7 +227,7 @@
// The instance getter shadows the other extensions method
extensionMethod(4);
// ^^^^^^^^^^^^^^^
-// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^
// [cfe] The method 'call' isn't defined for the class 'int'.
}
@@ -258,7 +258,7 @@
// The instance getter shadows the other extensions method
extensionMethod(4);
// ^^^^^^^^^^^^^^^
-// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// [cfe] 'extensionMethod' isn't a function or method and can't be invoked.
}
}
@@ -372,7 +372,7 @@
// The static getter shadows the other extensions method
extensionMethod(4);
// ^^^^^^^^^^^^^^^
-// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^
// [cfe] The method 'call' isn't defined for the class 'int'.
}
@@ -418,7 +418,7 @@
// The static getter shadows the other extensions method
extensionMethod(4);
// ^^^^^^^^^^^^^^^
-// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^
// [cfe] The method 'call' isn't defined for the class 'int'.
}
diff --git a/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart
index 6842e6b..dcb362a 100644
--- a/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart
@@ -259,8 +259,6 @@
// ^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
// [cfe] The method 'methodInExtensionScope' isn't defined for the class 'B'.
- // ^^^^^^^^^^^^^^^^^^^^^^
- // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
checkExtensionValue(t2);
}
diff --git a/tests/language_2/unsorted/mint_compares_test.dart b/tests/language_2/unsorted/mint_compares_test.dart
index aff8bd6..ef37d9a 100644
--- a/tests/language_2/unsorted/mint_compares_test.dart
+++ b/tests/language_2/unsorted/mint_compares_test.dart
@@ -80,6 +80,43 @@
Expect.isTrue(gt(4294967296, -1));
}
+compareTestWithZero(lt, lte, gt, gte, eq, ne) {
+ Expect.isFalse(lt(4294967296));
+ Expect.isFalse(lte(4294967296));
+ Expect.isTrue(gt(4294967296));
+ Expect.isTrue(gte(4294967296));
+ Expect.isFalse(eq(4294967296));
+ Expect.isTrue(ne(4294967296));
+
+ Expect.isTrue(lt(-1));
+ Expect.isTrue(lte(-1));
+ Expect.isFalse(gt(-1));
+ Expect.isFalse(gte(-1));
+ Expect.isFalse(eq(-1));
+ Expect.isTrue(ne(-1));
+
+ Expect.isTrue(lt(-2));
+ Expect.isTrue(lte(-2));
+ Expect.isFalse(gt(-2));
+ Expect.isFalse(gte(-2));
+ Expect.isFalse(eq(-2));
+ Expect.isTrue(ne(-2));
+
+ Expect.isTrue(lt(-4294967296));
+ Expect.isTrue(lte(-4294967296));
+ Expect.isFalse(gt(-4294967296));
+ Expect.isFalse(gte(-4294967296));
+ Expect.isFalse(eq(-4294967296));
+ Expect.isTrue(ne(-4294967296));
+
+ Expect.isFalse(lt(0));
+ Expect.isTrue(lte(0));
+ Expect.isFalse(gt(0));
+ Expect.isTrue(gte(0));
+ Expect.isTrue(eq(0));
+ Expect.isFalse(ne(0));
+}
+
bool lt1(a, b) => a < b;
bool lte1(a, b) => a <= b;
bool gt1(a, b) => a > b;
@@ -90,10 +127,27 @@
bool gt2(a, b) => a > b ? true : false;
bool gte2(a, b) => a >= b ? true : false;
+bool int_lt1(int a) => a < 0;
+bool int_lte1(int a) => a <= 0;
+bool int_gt1(int a) => a > 0;
+bool int_gte1(int a) => a >= 0;
+bool int_eq1(int a) => a == 0;
+bool int_ne1(int a) => a != 0;
+
+bool int_lt2(int a) => a < 0 ? true : false;
+bool int_lte2(int a) => a <= 0 ? true : false;
+bool int_gt2(int a) => a > 0 ? true : false;
+bool int_gte2(int a) => a >= 0 ? true : false;
+bool int_eq2(int a) => a == 0 ? true : false;
+bool int_ne2(int a) => a != 0 ? true : false;
+
main() {
for (var i = 0; i < 20; i++) {
compareTest();
compareTest2(lt1, lte1, gt1, gte1);
compareTest2(lt2, lte2, gt2, gte2);
+
+ compareTestWithZero(int_lt1, int_lte1, int_gt1, int_gte1, int_eq1, int_ne1);
+ compareTestWithZero(int_lt2, int_lte2, int_gt2, int_gte2, int_eq2, int_ne2);
}
}
diff --git a/tools/VERSION b/tools/VERSION
index 28a2d71..bc4e037 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
MAJOR 2
MINOR 8
PATCH 0
-PRERELEASE 1
+PRERELEASE 2
PRERELEASE_PATCH 0
ABI_VERSION 27
OLDEST_SUPPORTED_ABI_VERSION 27
diff --git a/tools/migration/bin/progress.dart b/tools/migration/bin/progress.dart
index 6b3b180..4a1c3dc 100644
--- a/tools/migration/bin/progress.dart
+++ b/tools/migration/bin/progress.dart
@@ -2,6 +2,10 @@
// 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';
+
+import 'package:path/path.dart' as p;
+
import 'package:migration/src/io.dart';
import 'package:migration/src/test_directories.dart';
@@ -37,34 +41,46 @@
var totalMigratedFiles = 0;
var totalMigratedLines = 0;
- for (var dir in legacyRootDirs) {
- var files = 0;
- var lines = 0;
- var migratedFiles = 0;
- var migratedLines = 0;
+ for (var rootDir in legacyRootDirs) {
+ var subdirs = Directory(p.join(testRoot, rootDir))
+ .listSync()
+ .where((subdir) => subdir is Directory)
+ .map((subdir) => p.relative(subdir.path, from: testRoot))
+ .toList();
+ subdirs.add(rootDir);
+ subdirs.sort();
- for (var legacyPath in listFiles(dir)) {
- if (!_includeNonCoreLibs && _nonCoreLibs.any(legacyPath.startsWith)) {
- continue;
+ for (var dir in subdirs) {
+ var files = 0;
+ var lines = 0;
+ var migratedFiles = 0;
+ var migratedLines = 0;
+
+ for (var legacyPath in listFiles(dir)) {
+ if (!_includeNonCoreLibs && _nonCoreLibs.any(legacyPath.startsWith)) {
+ continue;
+ }
+
+ files++;
+ var sourceLines = readFileLines(legacyPath);
+ lines += sourceLines.length;
+
+ var nnbdPath = toNnbdPath(legacyPath);
+ if (fileExists(nnbdPath) ||
+ sourceLines.any((line) => line.contains(_nonMigratedMarker))) {
+ migratedFiles++;
+ migratedLines += sourceLines.length;
+ }
}
- files++;
- var sourceLines = readFileLines(legacyPath);
- lines += sourceLines.length;
+ if (files == 0) continue;
- var nnbdPath = toNnbdPath(legacyPath);
- if (fileExists(nnbdPath) ||
- sourceLines.any((line) => line.contains(_nonMigratedMarker))) {
- migratedFiles++;
- migratedLines += sourceLines.length;
- }
+ _show(dir, migratedFiles, files, migratedLines, lines);
+ totalFiles += files;
+ totalLines += lines;
+ totalMigratedFiles += migratedFiles;
+ totalMigratedLines += migratedLines;
}
-
- _show(dir, migratedFiles, files, migratedLines, lines);
- totalFiles += files;
- totalLines += lines;
- totalMigratedFiles += migratedFiles;
- totalMigratedLines += migratedLines;
}
print("");
@@ -82,12 +98,17 @@
var migratedDays = migratedLines / _linesPerDay;
var daysLeft = days - migratedDays;
- print("${label.padRight(12)} ${pad(migratedFiles, 4)}/${pad(files, 4)} "
+ var daysLeftString = ", ${pad(daysLeft.toStringAsFixed(2), 6)}/"
+ "${pad(days.toStringAsFixed(2), 5)} days left";
+ if (migratedLines == 0) {
+ daysLeftString = ", ${pad(daysLeft.toStringAsFixed(2), 6)} days left";
+ } else if (migratedLines == lines) {
+ daysLeftString = "";
+ }
+
+ print("${label.padRight(40)} ${pad(migratedFiles, 4)}/${pad(files, 4)} "
"files (${percent(migratedFiles, files)}%), "
"${pad(migratedLines, 6)}/${pad(lines, 6)} "
- "lines (${percent(migratedLines, lines)}%), "
- "${pad(migratedDays.toStringAsFixed(2), 6)}/"
- "${pad(days.toStringAsFixed(2), 5)} "
- "days (${percent(migratedDays, days)}%), "
- "${pad(daysLeft.toStringAsFixed(2), 5)} days left");
+ "lines (${percent(migratedLines, lines)}%)"
+ "$daysLeftString");
}