Version 2.12.0-133.6.beta
* Cherry-pick refs/changes/04/176504/2 to beta
* Cherry-pick 4c2edfd5b9fe33139aad7e9ca021bd8530f47986 to beta
* Cherry-pick 17b43ca84677781ade9d4da48d32d0ea950ea2e0 to beta
* Cherry-pick abe144c30fdcdfba3573a36a59da5d0ac6e28c5f to beta
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b0d0877..a0982c4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,6 +30,14 @@
* `LinkedList` made it explicit that elements are compared by identity,
and updated `contains` to take advantage of this.
+#### `dart:html`
+
+* `EventStreamSubscription.cancel` has been updated to retain its synchronous
+ timing when running in both sound and unsound null safety modes. See issue
+ [#44157][] for more details.
+
+[#44157]: https://github.com/dart-lang/sdk/issues/44157
+
### Dart VM
* **Breaking Change** [#42312][]: `Dart_WeakPersistentHandle`s will no longer
diff --git a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
index e66c221..3e2a88f 100644
--- a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
@@ -111,6 +111,72 @@
''');
}
+ Future<void> test_suggestion_class_part() async {
+ var a_path = convertPath('/home/test/lib/a.dart');
+ var b_path = convertPath('/home/test/lib/b.dart');
+ var a_uriStr = 'package:test/a.dart';
+
+ newFile(a_path, content: r'''
+part 'b.dart';
+class A {}
+''');
+
+ newFile(b_path, content: r'''
+part of 'a.dart';
+class B {}
+''');
+
+ var set = await waitForSetWithUri(a_uriStr);
+ assertJsonText(_getSuggestion(set, 'A', kind: ElementKind.CLASS), '''
+{
+ "label": "A",
+ "declaringLibraryUri": "package:test/a.dart",
+ "element": {
+ "kind": "CLASS",
+ "name": "A",
+ "location": {
+ "file": ${jsonOfPath(a_path)},
+ "offset": 21,
+ "length": 0,
+ "startLine": 2,
+ "startColumn": 7
+ },
+ "flags": 0
+ },
+ "relevanceTags": [
+ "ElementKind.CLASS",
+ "package:test/a.dart::A",
+ "A"
+ ]
+}
+''');
+
+ // We should not get duplicate relevance tags.
+ assertJsonText(_getSuggestion(set, 'B', kind: ElementKind.CLASS), '''
+{
+ "label": "B",
+ "declaringLibraryUri": "package:test/a.dart",
+ "element": {
+ "kind": "CLASS",
+ "name": "B",
+ "location": {
+ "file": ${jsonOfPath(b_path)},
+ "offset": 24,
+ "length": 0,
+ "startLine": 2,
+ "startColumn": 7
+ },
+ "flags": 0
+ },
+ "relevanceTags": [
+ "ElementKind.CLASS",
+ "package:test/a.dart::B",
+ "B"
+ ]
+}
+''');
+ }
+
Future<void> test_suggestion_enum() async {
var path = convertPath('/home/test/lib/a.dart');
var uriStr = 'package:test/a.dart';
@@ -307,7 +373,9 @@
}
static AvailableSuggestion _getSuggestion(
- AvailableSuggestionSet set, String label) {
- return set.items.singleWhere((s) => s.label == label);
+ AvailableSuggestionSet set, String label,
+ {ElementKind kind}) {
+ return set.items.singleWhere(
+ (s) => s.label == label && (kind == null || s.element.kind == kind));
}
}
diff --git a/pkg/analyzer/lib/src/services/available_declarations.dart b/pkg/analyzer/lib/src/services/available_declarations.dart
index 5227a27..e0f631d 100644
--- a/pkg/analyzer/lib/src/services/available_declarations.dart
+++ b/pkg/analyzer/lib/src/services/available_declarations.dart
@@ -58,7 +58,8 @@
final String returnType;
final String typeParameters;
- List<String> _relevanceTags;
+ final List<String> _relevanceTagsInFile;
+ List<String> _relevanceTagsInLibrary = const [];
Uri _locationLibraryUri;
Declaration({
@@ -85,15 +86,18 @@
@required this.parameterNames,
@required this.parameterTypes,
@required this.parent,
- @required List<String> relevanceTags,
+ @required List<String> relevanceTagsInFile,
@required this.requiredParameterCount,
@required this.returnType,
@required this.typeParameters,
- }) : _relevanceTags = relevanceTags;
+ }) : _relevanceTagsInFile = relevanceTagsInFile;
Uri get locationLibraryUri => _locationLibraryUri;
- List<String> get relevanceTags => _relevanceTags;
+ List<String> get relevanceTags => [
+ ..._relevanceTagsInFile,
+ ..._relevanceTagsInLibrary,
+ ];
@override
String toString() {
@@ -927,9 +931,6 @@
var kind = kindFromIdl(d.kind);
var relevanceTags = d.relevanceTags.toList();
- if (relevanceTags.isEmpty) {
- relevanceTags = null;
- }
var children = <Declaration>[];
var declaration = Declaration(
@@ -960,7 +961,7 @@
parameterNames: hasParameters ? d.parameterNames.toList() : null,
parameterTypes: hasParameters ? d.parameterTypes.toList() : null,
parent: parent,
- relevanceTags: relevanceTags,
+ relevanceTagsInFile: relevanceTags,
requiredParameterCount: hasParameters ? d.requiredParameterCount : null,
returnType: hasReturnType ? d.returnType : null,
typeParameters: hasTypeParameters ? d.typeParameters : null,
@@ -1082,7 +1083,7 @@
parameters: d.parameters,
parameterNames: d.parameterNames,
parameterTypes: d.parameterTypes,
- relevanceTags: d.relevanceTags,
+ relevanceTags: d._relevanceTagsInFile,
requiredParameterCount: d.requiredParameterCount,
returnType: d.returnType,
typeParameters: d.typeParameters,
@@ -1130,7 +1131,7 @@
class _File {
/// The version of data format, should be incremented on every format change.
- static const int DATA_VERSION = 15;
+ static const int DATA_VERSION = 16;
/// The next value for [id].
static int _nextId = 0;
@@ -1385,7 +1386,7 @@
parameterNames: parameterNames,
parameterTypes: parameterTypes,
parent: parent,
- relevanceTags: relevanceTags,
+ relevanceTagsInFile: relevanceTags,
requiredParameterCount: requiredParameterCount,
returnType: returnType,
typeParameters: typeParameters,
@@ -1557,7 +1558,7 @@
parameterNames: [],
parameterTypes: [],
parent: classDeclaration,
- relevanceTags: ['ElementKind.CONSTRUCTOR'],
+ relevanceTagsInFile: ['ElementKind.CONSTRUCTOR'],
requiredParameterCount: 0,
returnType: node.name.name,
typeParameters: null,
@@ -1711,10 +1712,7 @@
void _computeRelevanceTags(List<Declaration> declarations) {
for (var declaration in declarations) {
var tags = RelevanceTags._forDeclaration(uriStr, declaration);
- if (tags != null) {
- declaration._relevanceTags ??= [];
- declaration._relevanceTags.addAll(tags);
- }
+ declaration._relevanceTagsInLibrary = tags ?? const [];
_computeRelevanceTags(declaration.children);
}
}
diff --git a/pkg/analyzer/test/src/services/available_declarations_test.dart b/pkg/analyzer/test/src/services/available_declarations_test.dart
index 3e2aa12..b155619 100644
--- a/pkg/analyzer/test/src/services/available_declarations_test.dart
+++ b/pkg/analyzer/test/src/services/available_declarations_test.dart
@@ -955,6 +955,60 @@
]);
}
+ /// https://github.com/dart-lang/sdk/issues/44353
+ test_updated_library_hasPart() async {
+ var a = convertPath('/home/test/lib/a.dart');
+ var b = convertPath('/home/test/lib/b.dart');
+
+ newFile(a, content: r'''
+part 'b.dart';
+class A {}
+''');
+ newFile(b, content: r'''
+part of 'a.dart';
+class B {}
+''');
+ tracker.addContext(testAnalysisContext);
+
+ await _doAllTrackerWork();
+
+ var library = _getLibrary('package:test/a.dart');
+ _assertDeclaration(
+ _getDeclaration(library.declarations, 'A'),
+ 'A',
+ DeclarationKind.CLASS,
+ relevanceTags: ['ElementKind.CLASS', 'package:test/a.dart::A'],
+ );
+ _assertDeclaration(
+ _getDeclaration(library.declarations, 'B'),
+ 'B',
+ DeclarationKind.CLASS,
+ relevanceTags: ['ElementKind.CLASS', 'package:test/a.dart::B'],
+ );
+
+ newFile(a, content: r'''
+part 'b.dart';
+class A2 {}
+''');
+ tracker.changeFile(a);
+ await _doAllTrackerWork();
+
+ // We should not get duplicate relevance tags, specifically in the part.
+ library = _getLibrary('package:test/a.dart');
+ _assertDeclaration(
+ _getDeclaration(library.declarations, 'A2'),
+ 'A2',
+ DeclarationKind.CLASS,
+ relevanceTags: ['ElementKind.CLASS', 'package:test/a.dart::A2'],
+ );
+ _assertDeclaration(
+ _getDeclaration(library.declarations, 'B'),
+ 'B',
+ DeclarationKind.CLASS,
+ relevanceTags: ['ElementKind.CLASS', 'package:test/a.dart::B'],
+ );
+ }
+
test_updated_library_to_part() async {
var a = convertPath('/home/test/lib/a.dart');
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index db85b79..d3f637a 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -345,7 +345,7 @@
// Visit each library and emit its code.
//
- // NOTE: clases are not necessarily emitted in this order.
+ // NOTE: classes are not necessarily emitted in this order.
// Order will be changed as needed so the resulting code can execute.
// This is done by forward declaring items.
libraries.forEach(_emitLibrary);
@@ -375,6 +375,30 @@
// Declare imports and extension symbols
emitImportsAndExtensionSymbols(items);
+ // Insert a check that runs when loading this module to verify that the null
+ // safety mode it was compiled in matches the mode used when compiling the
+ // dart sdk module.
+ //
+ // This serves as a sanity check at runtime that we don't have an
+ // infrastructure issue that loaded js files compiled with different modes
+ // into the same application.
+ js_ast.LiteralBool soundNullSafety;
+ switch (component.mode) {
+ case NonNullableByDefaultCompiledMode.Strong:
+ soundNullSafety = js_ast.LiteralBool(true);
+ break;
+ case NonNullableByDefaultCompiledMode.Weak:
+ soundNullSafety = js_ast.LiteralBool(false);
+ break;
+ default:
+ throw StateError('Unsupported Null Safety mode ${component.mode}, '
+ 'in ${component?.location?.file}.');
+ }
+ if (!isBuildingSdk) {
+ items.add(
+ runtimeStatement('_checkModuleNullSafetyMode(#)', [soundNullSafety]));
+ }
+
// Discharge the type table cache variables and
// hoisted definitions.
items.addAll(_typeTable.discharge());
@@ -5487,27 +5511,6 @@
js_ast.Expression visitAsExpression(AsExpression node) {
var fromExpr = node.operand;
var jsFrom = _visitExpression(fromExpr);
-
- // The `_EventStreamSubscription.cancel()` method dart:html returns null in
- // weak mode. This causes unwanted warnings/failures when you turn on the
- // weak mode warnings/errors so we remove these specific runtime casts.
- // TODO(44157) Remove this workaround once it returns a consistent type.
- if (_isWebLibrary(currentLibraryUri) && node.parent is ReturnStatement) {
- var parent = node.parent;
- while (parent != null && parent is! FunctionNode) {
- parent = parent?.parent;
- }
- parent = parent?.parent;
- if (parent is Procedure) {
- if (parent.enclosingClass != null &&
- parent.enclosingClass.name == '_EventStreamSubscription' &&
- parent.name.name == 'cancel') {
- // Ignore these casts and just emit the expression.
- return jsFrom;
- }
- }
- }
-
var to = node.type;
var from = fromExpr.getStaticType(_staticTypeContext);
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 236a3ef..1209475 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -65,7 +65,8 @@
..omitPlatform = true
..sdkSummary = sdkRoot.resolve(
soundNullSafety ? sdkSoundSummaryPath : sdkUnsoundSummaryPath)
- ..environmentDefines = const {};
+ ..environmentDefines = const {}
+ ..nnbdMode = soundNullSafety ? NnbdMode.Strong : NnbdMode.Weak;
return options;
}
diff --git a/pkg/frontend_server/lib/src/javascript_bundle.dart b/pkg/frontend_server/lib/src/javascript_bundle.dart
index d67f9bc..924c551 100644
--- a/pkg/frontend_server/lib/src/javascript_bundle.dart
+++ b/pkg/frontend_server/lib/src/javascript_bundle.dart
@@ -19,7 +19,7 @@
/// JavaScript modules concatenated together, and a second containing the byte
/// offsets by module name for each JavaScript module in JSON format.
///
-/// Ths format is analgous to the dill and .incremental.dill in that during
+/// Ths format is analogous to the dill and .incremental.dill in that during
/// an incremental build, a different file is written for each which contains
/// only the updated libraries.
class JavaScriptBundler {
@@ -42,6 +42,8 @@
nameRoot: _originalComponent.root,
uriToSource: _originalComponent.uriToSource,
);
+ summaryComponent.setMainMethodAndMode(
+ null, false, _originalComponent.mode);
_summaries.add(summaryComponent);
_summaryUris.add(uri);
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index 9715fb6..ea7932f 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -1938,7 +1938,8 @@
CompilationResult result =
CompilationResult.parse(compiledResult.status);
count++;
- // Request to 'compile', which results in full JavaScript and no metadata
+ // Request to 'compile', which results in full JavaScript and no
+ // metadata.
expect(result.errorsCount, equals(0));
expect(sourceFile.existsSync(), equals(true));
expect(manifestFile.existsSync(), equals(true));
@@ -2018,7 +2019,7 @@
CompilationResult result =
CompilationResult.parse(compiledResult.status);
count++;
- // Request to 'compile', which results in full JavaScript and no metadata
+ // Request to 'compile', which results in full JavaScript and metadata.
expect(result.errorsCount, equals(0));
expect(sourceFile.existsSync(), equals(true));
expect(manifestFile.existsSync(), equals(true));
@@ -2034,6 +2035,178 @@
expect(count, 1);
});
+ test('compile to JavaScript all modules with unsound null safety',
+ () async {
+ var file = File('${tempDir.path}/foo.dart')..createSync();
+ file.writeAsStringSync("import 'bar.dart'; "
+ "typedef myType = void Function(int); main() { fn is myType; }\n");
+ file = File('${tempDir.path}/bar.dart')..createSync();
+ file.writeAsStringSync("void Function(int) fn = (int i) => null;\n");
+ var library = 'package:hello/foo.dart';
+
+ var dillFile = File('${tempDir.path}/app.dill');
+ var sourceFile = File('${dillFile.path}.sources');
+
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./",
+ "languageVersion": "2.9"
+ }
+ ]
+ }
+ ''');
+
+ final List<String> args = <String>[
+ '--verbose',
+ '--no-sound-null-safety',
+ '--sdk-root=${sdkRoot.toFilePath()}',
+ '--incremental',
+ '--platform=${ddcPlatformKernelWeak.path}',
+ '--output-dill=${dillFile.path}',
+ '--target=dartdevc',
+ '--packages=${package_config.path}'
+ ];
+
+ final StreamController<List<int>> streamController =
+ StreamController<List<int>>();
+ final StreamController<List<int>> stdoutStreamController =
+ StreamController<List<int>>();
+ final IOSink ioSink = IOSink(stdoutStreamController.sink);
+ StreamController<Result> receivedResults = StreamController<Result>();
+ final outputParser = OutputParser(receivedResults);
+ stdoutStreamController.stream
+ .transform(utf8.decoder)
+ .transform(const LineSplitter())
+ .listen(outputParser.listener);
+
+ Future<int> result =
+ starter(args, input: streamController.stream, output: ioSink);
+ streamController.add('compile $library\n'.codeUnits);
+ var count = 0;
+ var expectationCompleter = Completer<bool>();
+ receivedResults.stream.listen((Result compiledResult) {
+ CompilationResult result =
+ CompilationResult.parse(compiledResult.status);
+ count++;
+ // Request to 'compile', which results in full JavaScript and no
+ // metadata.
+ expect(result.errorsCount, equals(0));
+ expect(sourceFile.existsSync(), equals(true));
+ expect(result.filename, dillFile.path);
+
+ var source = sourceFile.readAsStringSync();
+ // Split on the comment at the end of each module.
+ var jsModules = source.split(RegExp("\/\/# sourceMappingURL=.*\.map"));
+
+ // Both modules should include the unsound null safety check.
+ expect(
+ jsModules[0], contains('dart._checkModuleNullSafetyMode(false);'));
+ expect(
+ jsModules[1], contains('dart._checkModuleNullSafetyMode(false);'));
+ streamController.add('accept\n'.codeUnits);
+ outputParser.expectSources = false;
+ streamController.add('quit\n'.codeUnits);
+ expectationCompleter.complete(true);
+ });
+
+ await expectationCompleter.future;
+ expect(await result, 0);
+ expect(count, 1);
+ }, timeout: Timeout.none);
+
+ test('compile to JavaScript, all modules with sound null safety', () async {
+ var file = File('${tempDir.path}/foo.dart')..createSync();
+ file.writeAsStringSync(
+ "import 'bar.dart'; typedef myType = void Function(int); "
+ "main() { fn is myType; }\n");
+ file = File('${tempDir.path}/bar.dart')..createSync();
+ file.writeAsStringSync("void Function(int) fn = (int i) => null;\n");
+
+ var package_config =
+ File('${tempDir.path}/.dart_tool/package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "hello",
+ "rootUri": "../",
+ "packageUri": "./"
+ }
+ ]
+ }
+ ''');
+
+ var library = 'package:hello/foo.dart';
+
+ var dillFile = File('${tempDir.path}/app.dill');
+ var sourceFile = File('${dillFile.path}.sources');
+
+ final List<String> args = <String>[
+ '--sdk-root=${sdkRoot.toFilePath()}',
+ '--incremental',
+ '--platform=${ddcPlatformKernel.path}',
+ '--output-dill=${dillFile.path}',
+ '--target=dartdevc',
+ '--packages=${package_config.path}',
+ ];
+
+ final StreamController<List<int>> streamController =
+ StreamController<List<int>>();
+ final StreamController<List<int>> stdoutStreamController =
+ StreamController<List<int>>();
+ final IOSink ioSink = IOSink(stdoutStreamController.sink);
+ StreamController<Result> receivedResults = StreamController<Result>();
+ final outputParser = OutputParser(receivedResults);
+ stdoutStreamController.stream
+ .transform(utf8.decoder)
+ .transform(const LineSplitter())
+ .listen(outputParser.listener);
+
+ Future<int> result =
+ starter(args, input: streamController.stream, output: ioSink);
+ streamController.add('compile $library\n'.codeUnits);
+ var count = 0;
+ var expectationCompleter = Completer<bool>();
+ receivedResults.stream.listen((Result compiledResult) {
+ CompilationResult result =
+ CompilationResult.parse(compiledResult.status);
+ count++;
+ // Request to 'compile', which results in full JavaScript and no
+ // metadata.
+ expect(result.errorsCount, equals(0));
+ expect(sourceFile.existsSync(), equals(true));
+ expect(result.filename, dillFile.path);
+
+ var source = sourceFile.readAsStringSync();
+ // Split on the comment at the end of each module.
+ var jsModules = source.split(RegExp("\/\/# sourceMappingURL=.*\.map"));
+
+ // Both modules should include the sound null safety validation.
+ expect(
+ jsModules[0], contains('dart._checkModuleNullSafetyMode(true);'));
+ expect(
+ jsModules[1], contains('dart._checkModuleNullSafetyMode(true);'));
+ streamController.add('accept\n'.codeUnits);
+ outputParser.expectSources = false;
+ streamController.add('quit\n'.codeUnits);
+ expectationCompleter.complete(true);
+ });
+
+ await expectationCompleter.future;
+ expect(await result, 0);
+ expect(count, 1);
+ });
+
test('compile expression to Javascript', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
file.writeAsStringSync("main() {\n}\n");
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
index 3ec1689..fd80d9c 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
@@ -24,6 +24,21 @@
throw AssertionErrorImpl(message, fileUri, line, column, conditionSource);
}
+/// Throws if [isModuleSound] does not match the null safety mode of this SDK.
+///
+/// The call to this method is inserted into every module at compile time when
+/// the compile time null safety mode for the module is known.
+void _checkModuleNullSafetyMode(@notNull bool isModuleSound) {
+ if (isModuleSound != compileTimeFlag('soundNullSafety')) {
+ var sdkMode = compileTimeFlag('soundNullSafety') ? 'sound' : 'unsound';
+ var moduleMode = isModuleSound ? 'sound' : 'unsound';
+
+ throw AssertionError('The null safety mode of the Dart SDK module '
+ '($sdkMode) does not match the null safety mode of this module '
+ '($moduleMode).');
+ }
+}
+
final _nullFailedSet = JS('!', 'new Set()');
String _nullFailedMessage(variableName) =>
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index a79aff6..bc7bdfb 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -37285,18 +37285,13 @@
}
Future cancel() {
- // Check for strong mode. This function can no longer return null in strong
- // mode, so only return null in weak mode to preserve synchronous timing.
- // See issue 41653 for more details.
- dynamic emptyFuture =
- typeAcceptsNull<Event>() ? null : Future<void>.value();
- if (_canceled) return emptyFuture as Future;
+ if (_canceled) return nullFuture;
_unlisten();
// Clear out the target to indicate this is complete.
_target = null;
_onData = null;
- return emptyFuture as Future;
+ return nullFuture;
}
bool get _canceled => _target == null;
diff --git a/tools/VERSION b/tools/VERSION
index 028a34a..4b12615 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 12
PATCH 0
PRERELEASE 133
-PRERELEASE_PATCH 2
\ No newline at end of file
+PRERELEASE_PATCH 6
\ No newline at end of file
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index fe01be9..feadc26 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -248,18 +248,13 @@
}
Future cancel() {
- // Check for strong mode. This function can no longer return null in strong
- // mode, so only return null in weak mode to preserve synchronous timing.
- // See issue 41653 for more details.
- dynamic emptyFuture =
- typeAcceptsNull<Event>() ? null : Future<void>.value();
- if (_canceled) return emptyFuture as Future;
+ if (_canceled) return nullFuture;
_unlisten();
// Clear out the target to indicate this is complete.
_target = null;
_onData = null;
- return emptyFuture as Future;
+ return nullFuture;
}
bool get _canceled => _target == null;