Version 2.12.0-51.0.dev
Merge commit 'f0c9321b1430f3904097ee2a0c52b01d5e28944f' into 'dev'
diff --git a/DEPS b/DEPS
index 4dc0fef..5621e3d 100644
--- a/DEPS
+++ b/DEPS
@@ -146,7 +146,7 @@
"source_maps-0.9.4_rev": "38524",
"source_maps_rev": "53eb92ccfe6e64924054f83038a534b959b12b3e",
"source_span_rev": "49ff31eabebed0da0ae6634124f8ba5c6fbf57f1",
- "sse_tag": "814924bac4d3cd56f40d05b3427e69f3e966d139",
+ "sse_tag": "9a486d058a17e880afa9cc1c3c0dd8bad726bcbc",
"stack_trace_tag": "6788afc61875079b71b3d1c3e65aeaa6a25cbc2f",
"stagehand_tag": "v3.3.11",
"stream_channel_tag": "d7251e61253ec389ee6e045ee1042311bced8f1d",
@@ -165,7 +165,7 @@
"web_components_rev": "8f57dac273412a7172c8ade6f361b407e2e4ed02",
"web_socket_channel_rev": "490061ef0e22d3c8460ad2802f9948219365ad6b",
"WebCore_rev": "fb11e887f77919450e497344da570d780e078bc8",
- "yaml_rev": "925c406f8bdb06ce7935f0a7d03187b36c6b62d0",
+ "yaml_rev": "cca02c9e4f6826d62644901ed65c6d72b90a0713",
"zlib_rev": "c44fb7248079cc3d5563b14b3f758aee60d6b415",
"crashpad_rev": "bf327d8ceb6a669607b0dbab5a83a275d03f99ed",
"minichromium_rev": "8d641e30a8b12088649606b912c2bc4947419ccc",
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index e739602..2e797f0 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -71,6 +71,7 @@
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
@@ -351,11 +352,13 @@
/// diagnostics.
ChangeBuilder builder;
+ /// A map associating libraries to fixes with change counts.
+ final ChangeMap changeMap = ChangeMap();
+
/// Initialize a newly created processor to create fixes for diagnostics in
/// libraries in the [workspace].
- BulkFixProcessor(this.instrumentationService, this.workspace) {
- builder = ChangeBuilder(workspace: workspace);
- }
+ BulkFixProcessor(this.instrumentationService, this.workspace)
+ : builder = ChangeBuilder(workspace: workspace);
/// Return a change builder that has been used to create fixes for the
/// diagnostics in the libraries in the given [contexts].
@@ -431,19 +434,38 @@
}
}
+ int computeChangeHash() {
+ var hash = 0;
+ var edits = builder.sourceChange.edits;
+ for (var i = 0; i < edits.length; ++i) {
+ hash = JenkinsSmiHash.combine(hash, edits[i].hashCode);
+ }
+ return JenkinsSmiHash.finish(hash);
+ }
+
+ Future<void> generate(CorrectionProducer producer, String code) async {
+ var oldHash = computeChangeHash();
+ await compute(producer);
+ var newHash = computeChangeHash();
+ if (newHash != oldHash) {
+ changeMap.add(result.path, code);
+ }
+ }
+
var errorCode = diagnostic.errorCode;
try {
+ var codeName = errorCode.name;
if (errorCode is LintCode) {
- var generators = lintProducerMap[errorCode.name];
+ var generators = lintProducerMap[codeName];
if (generators != null) {
for (var generator in generators) {
- await compute(generator());
+ await generate(generator(), codeName);
}
}
} else {
var generator = nonLintProducerMap[errorCode];
if (generator != null) {
- await compute(generator());
+ await generate(generator(), codeName);
}
var multiGenerators = nonLintMultiProducerMap[errorCode];
if (multiGenerators != null) {
@@ -451,7 +473,7 @@
var multiProducer = multiGenerator();
multiProducer.configure(context);
for (var producer in multiProducer.producers) {
- await compute(producer);
+ await generate(producer, codeName);
}
}
}
@@ -464,3 +486,15 @@
}
}
}
+
+/// Maps changes to library paths.
+class ChangeMap {
+ /// Map of paths to maps of codes to counts.
+ final Map<String, Map<String, int>> libraryMap = {};
+
+ /// Add an entry for the given [code] in the given [libraryPath].
+ void add(String libraryPath, String code) {
+ var changes = libraryMap.putIfAbsent(libraryPath, () => {});
+ changes.update(code, (value) => value + 1, ifAbsent: () => 1);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
index 3e9e14c..1f45cc4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
@@ -36,7 +36,7 @@
}
Future<void> assertHasFix(String expected) async {
- change = await _computeFixes();
+ change = await _computeSourceChange();
// apply to "file"
var fileEdits = change.edits;
@@ -48,11 +48,22 @@
}
Future<void> assertNoFix() async {
- change = await _computeFixes();
+ change = await _computeSourceChange();
var fileEdits = change.edits;
expect(fileEdits, isEmpty);
}
+ /// Computes fixes for the specified [testUnit].
+ Future<BulkFixProcessor> computeFixes() async {
+ var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
+ var analysisContext = contextFor(testFile);
+ tracker.addContext(analysisContext);
+ var processor =
+ BulkFixProcessor(InstrumentationService.NULL_SERVICE, workspace);
+ await processor.fixErrors([analysisContext]);
+ return processor;
+ }
+
@override
void setUp() {
super.setUp();
@@ -60,15 +71,10 @@
_createAnalysisOptionsFile();
}
- /// Computes fixes for the given [error] in [testUnit].
- Future<SourceChange> _computeFixes() async {
- var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
- var analysisContext = contextFor(testFile);
- tracker.addContext(analysisContext);
- var changeBuilder =
- await BulkFixProcessor(InstrumentationService.NULL_SERVICE, workspace)
- .fixErrors([analysisContext]);
- return changeBuilder.sourceChange;
+ /// Returns the source change for computed fixes in the specified [testUnit].
+ Future<SourceChange> _computeSourceChange() async {
+ var processor = await computeFixes();
+ return processor.builder.sourceChange;
}
/// Create the analysis options file needed in order to correctly analyze the
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
new file mode 100644
index 0000000..8ac6ee0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'bulk_fix_processor.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ChangeMapTest);
+ });
+}
+
+@reflectiveTest
+class ChangeMapTest extends BulkFixProcessorTest {
+ Future<void> test_changeMap() async {
+ createAnalysisOptionsFile(experiments: experiments, lints: [
+ LintNames.annotate_overrides,
+ LintNames.unnecessary_new,
+ ]);
+
+ await resolveTestCode('''
+class A { }
+
+var a = new A();
+var aa = new A();
+''');
+
+ var processor = await computeFixes();
+ var changeMap = processor.changeMap;
+ var errors = changeMap.libraryMap[testFile];
+ expect(errors, hasLength(1));
+ expect(errors[LintNames.unnecessary_new], 2);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
index 3b98bfd..14012da 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
@@ -9,6 +9,7 @@
import 'add_diagnostic_property_reference_test.dart'
as add_diagnostic_property_reference;
import 'add_override_test.dart' as add_override;
+import 'bulk_fix_processor_test.dart' as bulk_fix_processor;
import 'convert_documentation_into_line_test.dart'
as convert_documentation_into_line;
import 'convert_map_from_iterable_to_for_literal_test.dart'
@@ -70,6 +71,7 @@
add_const.main();
add_diagnostic_property_reference.main();
add_override.main();
+ bulk_fix_processor.main();
convert_documentation_into_line.main();
convert_map_from_iterable_to_for_literal.main();
convert_to_contains.main();
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index c34d83f..d97ca2a 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -20,7 +20,7 @@
pub_semver: ^1.4.2
source_span: ^1.2.0
watcher: ^0.9.6
- yaml: ^2.1.2
+ yaml: ">=2.1.2 <4.0.0"
dev_dependencies:
analyzer_utilities:
path: ../analyzer_utilities
diff --git a/pkg/analyzer_cli/pubspec.yaml b/pkg/analyzer_cli/pubspec.yaml
index 4a8c027..a1980aa 100644
--- a/pkg/analyzer_cli/pubspec.yaml
+++ b/pkg/analyzer_cli/pubspec.yaml
@@ -17,7 +17,7 @@
meta: any
path: any
pub_semver: ^1.4.2
- yaml: ^2.1.2
+ yaml: any
dev_dependencies:
pedantic: ^1.9.0
diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
index 32be6a6..54979eb3 100644
--- a/pkg/dds/CHANGELOG.md
+++ b/pkg/dds/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 1.5.1
+- Improve internal error handling for situations with less than graceful
+ shutdowns.
+
# 1.5.0
- Added event caching for `Stdout`, `Stderr`, and `Extension` streams. When a
client subscribes to one of these streams, they will be sent up to 10,000
diff --git a/pkg/dds/lib/src/dds_impl.dart b/pkg/dds/lib/src/dds_impl.dart
index d2a6dcb..fbb6bba 100644
--- a/pkg/dds/lib/src/dds_impl.dart
+++ b/pkg/dds/lib/src/dds_impl.dart
@@ -4,6 +4,27 @@
part of dds;
+@visibleForTesting
+typedef PeerBuilder = Future<json_rpc.Peer> Function(WebSocketChannel, dynamic);
+
+@visibleForTesting
+typedef WebSocketBuilder = WebSocketChannel Function(Uri);
+
+@visibleForTesting
+PeerBuilder peerBuilder = _defaultPeerBuilder;
+
+@visibleForTesting
+WebSocketBuilder webSocketBuilder = _defaultWebSocketBuilder;
+
+Future<json_rpc.Peer> _defaultPeerBuilder(
+ WebSocketChannel ws, dynamic streamManager) async {
+ return _BinaryCompatiblePeer(ws, streamManager);
+}
+
+WebSocketChannel _defaultWebSocketBuilder(Uri uri) {
+ return WebSocketChannel.connect(uri.replace(scheme: 'ws'));
+}
+
class _DartDevelopmentService implements DartDevelopmentService {
_DartDevelopmentService(
this._remoteVmServiceUri, this._uri, this._authCodesEnabled, this._ipv6) {
@@ -19,8 +40,8 @@
final completer = Completer<void>();
// TODO(bkonyi): throw if we've already shutdown.
// Establish the connection to the VM service.
- _vmServiceSocket = WebSocketChannel.connect(remoteVmServiceWsUri);
- _vmServiceClient = _BinaryCompatiblePeer(_vmServiceSocket, _streamManager);
+ _vmServiceSocket = webSocketBuilder(remoteVmServiceWsUri);
+ _vmServiceClient = await peerBuilder(_vmServiceSocket, _streamManager);
// Setup the JSON RPC client with the VM service.
unawaited(
_vmServiceClient.listen().then(
@@ -37,11 +58,15 @@
onError: (e, st) {
shutdown();
if (!completer.isCompleted) {
- completer.completeError(e, st);
+ completer.completeError(
+ DartDevelopmentServiceException._(e.toString()),
+ st,
+ );
}
},
),
);
+
try {
// Setup stream event handling.
await streamManager.listen();
@@ -93,7 +118,9 @@
} on json_rpc.RpcException catch (e) {
await _server.close(force: true);
// _yieldControlToDDS fails if DDS is not the only VM service client.
- throw DartDevelopmentServiceException._(e.data['details']);
+ throw DartDevelopmentServiceException._(
+ e.data != null ? e.data['details'] : e.toString(),
+ );
}
_uri = tmpUri;
@@ -113,7 +140,7 @@
await clientManager.shutdown();
// Close connection to VM service.
- await _vmServiceSocket.sink.close();
+ await _vmServiceSocket?.sink?.close();
_done.complete();
}
diff --git a/pkg/dds/lib/src/stream_manager.dart b/pkg/dds/lib/src/stream_manager.dart
index 542fe91..20be940 100644
--- a/pkg/dds/lib/src/stream_manager.dart
+++ b/pkg/dds/lib/src/stream_manager.dart
@@ -208,9 +208,7 @@
(_) => null,
// Ignore 'stream not subscribed' errors and StateErrors which arise
// when DDS is shutting down.
- test: (e) =>
- (e is json_rpc.RpcException) ||
- (dds._shuttingDown && e is StateError),
+ test: (e) => (e is json_rpc.RpcException) || (e is StateError),
);
}
// Notify other service clients of service extensions that are being
diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
index d2fdbdb..a04a63c 100644
--- a/pkg/dds/pubspec.yaml
+++ b/pkg/dds/pubspec.yaml
@@ -3,7 +3,7 @@
A library used to spawn the Dart Developer Service, used to communicate with
a Dart VM Service instance.
-version: 1.5.0
+version: 1.5.1
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds
@@ -25,5 +25,5 @@
dev_dependencies:
shelf_static: ^0.2.8
test: ^1.0.0
- vm_service: ^4.0.0
+ vm_service: ^5.0.0
webdriver: ^2.1.2
diff --git a/pkg/dds/test/common/fakes.dart b/pkg/dds/test/common/fakes.dart
new file mode 100644
index 0000000..7e11f9d
--- /dev/null
+++ b/pkg/dds/test/common/fakes.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:test/fake.dart';
+import 'package:vm_service/vm_service.dart';
+
+/// [FakePeer] implements the bare minimum of the [Peer] interface needed for
+/// [DartDevelopmentService] to establish a connection with a VM service.
+///
+/// `sendRequest` can be overridden to provide custom handling for VM service
+/// RPCs and custom RPCs to control the state of the [FakePeer] instance from a
+/// VM service client request routed through a [DartDevelopmentService] instance.
+class FakePeer extends Fake implements json_rpc.Peer {
+ @override
+ Future<void> get done => doneCompleter.future;
+ final Completer<void> doneCompleter = Completer<void>();
+
+ bool get isClosed => doneCompleter.isCompleted;
+
+ @override
+ Future<void> listen() {
+ return done;
+ }
+
+ @override
+ void registerMethod(String name, Function callback) {}
+
+ @override
+ Future<dynamic> sendRequest(String method, [args]) async {
+ switch (method) {
+ case 'getVM':
+ return _buildResponse(VM(
+ name: 'Test',
+ architectureBits: 0,
+ hostCPU: '',
+ operatingSystem: '',
+ targetCPU: '',
+ version: '',
+ pid: 0,
+ startTime: 0,
+ isolates: [],
+ isolateGroups: [],
+ systemIsolateGroups: [],
+ systemIsolates: [],
+ ));
+ default:
+ return _buildResponse(Success());
+ }
+ }
+
+ Map<String, dynamic> _buildResponse(dynamic serviceObject) {
+ return {
+ 'json_rpc': '2.0',
+ 'id': _idCount++,
+ ...serviceObject.toJson(),
+ };
+ }
+
+ int _idCount = 0;
+}
diff --git a/pkg/dds/test/handles_client_disconnect_state_error_test.dart b/pkg/dds/test/handles_client_disconnect_state_error_test.dart
new file mode 100644
index 0000000..2bca092
--- /dev/null
+++ b/pkg/dds/test/handles_client_disconnect_state_error_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:dds/dds.dart';
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:pedantic/pedantic.dart';
+import 'package:test/test.dart';
+import 'package:web_socket_channel/web_socket_channel.dart';
+
+import 'common/fakes.dart';
+
+class StreamCancelDisconnectPeer extends FakePeer {
+ @override
+ Future<dynamic> sendRequest(String method, [args]) async {
+ final completer = Completer<dynamic>();
+ switch (method) {
+ case 'streamCancel':
+ completer.completeError(
+ StateError('The client closed with pending request "streamCancel".'),
+ );
+ // Notify listeners that this client is closed.
+ doneCompleter.complete();
+ break;
+ default:
+ completer.complete(await super.sendRequest(method, args));
+ }
+ return completer.future;
+ }
+}
+
+void main() {
+ webSocketBuilder = (Uri _) => null;
+ peerBuilder =
+ (WebSocketChannel _, dynamic __) async => StreamCancelDisconnectPeer();
+
+ test('StateError handled by _StreamManager.clientDisconnect', () async {
+ final dds = await DartDevelopmentService.startDartDevelopmentService(
+ Uri(scheme: 'http'));
+ final ws = await WebSocketChannel.connect(dds.uri.replace(scheme: 'ws'));
+
+ // Create a VM service client that connects to DDS.
+ final client = json_rpc.Client(ws.cast<String>());
+ unawaited(client.listen());
+
+ // Listen to a non-core DDS stream so that DDS will cancel it once the
+ // client disconnects.
+ await client.sendRequest('streamListen', {
+ 'streamId': 'Service',
+ });
+
+ // Closing the client should result in DDS cleaning up stream subscriptions
+ // with no more clients subscribed to them. This will result in
+ // streamCancel being invoked, which StreamCancelDisconnectPeer overrides
+ // to act as if the VM service has shutdown with the request in flight
+ // which would result in a StateError being thrown by sendRequest. This
+ // test ensures that this exception is handled and doesn't escape outside
+ // of DDS.
+ await client.close();
+ await dds.done;
+ });
+}
diff --git a/pkg/dds/test/handles_connection_closed_before_full_header.dart b/pkg/dds/test/handles_connection_closed_before_full_header.dart
new file mode 100644
index 0000000..65d6436
--- /dev/null
+++ b/pkg/dds/test/handles_connection_closed_before_full_header.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:dds/dds.dart';
+import 'package:test/test.dart';
+
+/// Simple socket server which immediately closes the first connection and
+/// shuts down. This causes the HTTP request to the server to fail with a
+/// WebSocketChannelException: connection closed before full header was
+/// received failure, which should be caught and surfaced in a
+/// [DartDevelopmentServiceException].
+Future<Uri> startTestServer() async {
+ final server = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
+ server.listen((Socket request) async {
+ await request.destroy();
+ await server.close();
+ });
+ return Uri(scheme: 'http', host: server.address.host, port: server.port);
+}
+
+/// Reproduction case for https://github.com/flutter/flutter/issues/69433
+void main() async {
+ test('Handle connection closed before full header received', () async {
+ final uri = await startTestServer();
+ try {
+ await DartDevelopmentService.startDartDevelopmentService(uri);
+ fail('Unexpected successful connection.');
+ } on DartDevelopmentServiceException catch (e) {
+ expect(e.toString().contains('WebSocketChannelException'), true);
+ }
+ });
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 5d79c5f..db85b79 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -5486,8 +5486,29 @@
@override
js_ast.Expression visitAsExpression(AsExpression node) {
var fromExpr = node.operand;
- var to = node.type;
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);
// If the check was put here by static analysis to ensure soundness, we
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index 65888a8..023d555 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -49,18 +49,18 @@
..addFlag('sound-null-safety',
help: 'Compile for sound null safety at runtime. Passed through to the '
'DDC binary. Defaults to false.',
- defaultsTo: false,
- negatable: true)
+ defaultsTo: false)
..addFlag('null-assertions',
help: 'Run with assertions that values passed to non-nullable method '
'parameters are not null.',
- defaultsTo: false,
- negatable: true)
+ defaultsTo: false)
..addFlag('native-null-assertions',
help: 'Run with assertions on non-nullable values returned from native '
'APIs.',
defaultsTo: true,
negatable: true)
+ ..addFlag('weak-null-safety-errors',
+ help: 'Treat weak null safety warnings as errors.', defaultsTo: false)
..addFlag('observe',
help:
'Run the compiler in the Dart VM with --observe. Implies --debug.',
@@ -86,7 +86,6 @@
abbr: 'v',
help: 'Echos the commands, arguments, and environment this script is '
'running.',
- negatable: false,
defaultsTo: false)
..addOption('vm-service-port',
help: 'Specify the observatory port. Implied --observe.');
@@ -115,19 +114,10 @@
var compile = mode == 'compile' || mode == 'all';
var run = mode == 'run' || mode == 'all';
var verbose = options['verbose'] as bool;
+ var soundNullSafety = options['sound-null-safety'] as bool;
var nonNullAsserts = options['null-assertions'] as bool;
var nativeNonNullAsserts = options['null-assertions'] as bool;
-
- var soundNullSafety = options['sound-null-safety'] as bool;
- // Enable null safety either by passing the `non-nullable` experiment flag or
- // `sound-null-safety`.
- var nnbd = experiments.contains('non-nullable') || soundNullSafety;
-
- // Ensure non-nullable is passed as a flag.
- if (soundNullSafety && !experiments.contains('non-nullable')) {
- experiments.add('non-nullable');
- }
-
+ var weakNullSafetyErrors = options['weak-null-safety-errors'] as bool;
var entry = p.canonicalize(options.rest.first);
var out = (options['out'] as String) ?? p.setExtension(entry, '.js');
var libRoot = p.dirname(entry);
@@ -275,11 +265,12 @@
require(['dart_sdk', '$basename'],
function(sdk, app) {
'use strict';
- if ($nnbd) {
- sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
- sdk.dart.nonNullAsserts($nonNullAsserts);
- sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
- }
+
+ sdk.dart.weakNullSafetyWarnings(
+ !($weakNullSafetyErrors || $soundNullSafety));
+ sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
+ sdk.dart.nonNullAsserts($nonNullAsserts);
+ sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
sdk._debugger.registerDevtoolsFormatter();
app.$libname.main([]);
});
@@ -311,11 +302,11 @@
sdk.dart.global.self = sdk.dart.global;
let main = require(\"./$basename\").$libname.main;
try {
- if ($nnbd) {
- sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
- sdk.dart.nonNullAsserts($nonNullAsserts);
- sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
- }
+ sdk.dart.weakNullSafetyWarnings(
+ !($weakNullSafetyErrors || $soundNullSafety));
+ sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
+ sdk.dart.nonNullAsserts($nonNullAsserts);
+ sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
sdk._isolate_helper.startRootIsolate(main, []);
} catch(e) {
if (!source_maps) {
@@ -346,14 +337,14 @@
load("$sdkJsPath/dart_sdk.js");
load("$out");
-let dart_sdk = dart_library.import('dart_sdk');
+let sdk = dart_library.import('dart_sdk');
// Create a self reference for JS interop tests that set fields on self.
-dart_sdk.dart.global.self = dart_sdk.dart.global;
-if ($nnbd) {
- dart_sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
- dart_sdk.dart.nonNullAsserts($nonNullAsserts);
- dart_sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
-}
+sdk.dart.global.self = sdk.dart.global;
+sdk.dart.weakNullSafetyWarnings(
+ !($weakNullSafetyErrors || $soundNullSafety));
+sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
+sdk.dart.nonNullAsserts($nonNullAsserts);
+sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
dart_library.start('$basename', '$libname');
''';
var d8File = p.setExtension(out, '.d8.js');
diff --git a/pkg/front_end/pubspec.yaml b/pkg/front_end/pubspec.yaml
index e34f9f2..77ae47b 100644
--- a/pkg/front_end/pubspec.yaml
+++ b/pkg/front_end/pubspec.yaml
@@ -38,7 +38,7 @@
vm_service:
path: ../vm_service
web_socket_channel: ^1.0.4
- yaml: '^2.1.12'
+ yaml: any
dependency_overrides:
_fe_analyzer_shared:
diff --git a/pkg/modular_test/pubspec.yaml b/pkg/modular_test/pubspec.yaml
index 19e04da..68974ee 100644
--- a/pkg/modular_test/pubspec.yaml
+++ b/pkg/modular_test/pubspec.yaml
@@ -10,8 +10,8 @@
dependencies:
args: any
- package_config: ^1.0.5
- yaml: ^2.1.15
+ package_config: any
+ yaml: any
dev_dependencies:
async_helper:
diff --git a/pkg/nnbd_migration/pubspec.yaml b/pkg/nnbd_migration/pubspec.yaml
index 7917b78..ed3de13 100644
--- a/pkg/nnbd_migration/pubspec.yaml
+++ b/pkg/nnbd_migration/pubspec.yaml
@@ -18,7 +18,7 @@
path: ^1.6.2
pub_semver: ^1.4.2
source_span: ^1.4.1
- yaml: ^2.1.15
+ yaml: any
dev_dependencies:
analyzer_utilities:
diff --git a/pkg/test_runner/lib/src/browser.dart b/pkg/test_runner/lib/src/browser.dart
index 521e3c9..6625a5a 100644
--- a/pkg/test_runner/lib/src/browser.dart
+++ b/pkg/test_runner/lib/src/browser.dart
@@ -147,9 +147,16 @@
/// [testJSDir] is the relative path to the build directory where the
/// dartdevc-generated JS file is stored. [nonNullAsserts] enables non-null
/// assertions for non-nullable method parameters when running with weak null
-/// safety.
-String dartdevcHtml(String testName, String testNameAlias, String testJSDir,
- Compiler compiler, NnbdMode mode, bool nonNullAsserts) {
+/// safety. [weakNullSafetyErrors] enables null safety type violations to throw
+/// when running in weak mode.
+String dartdevcHtml(
+ String testName,
+ String testNameAlias,
+ String testJSDir,
+ Compiler compiler,
+ NnbdMode mode,
+ bool nonNullAsserts,
+ bool weakNullSafetyErrors) {
var testId = pathToJSIdentifier(testName);
var testIdAlias = pathToJSIdentifier(testNameAlias);
var isNnbd = mode != NnbdMode.legacy;
@@ -233,7 +240,8 @@
};
if ($isNnbd) {
- sdk.dart.weakNullSafetyWarnings(!$isNnbdStrong);
+ sdk.dart.weakNullSafetyWarnings(!($weakNullSafetyErrors || $isNnbdStrong));
+ sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
sdk.dart.nonNullAsserts($nonNullAsserts);
}
diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart
index 53af2c7..91e0731 100644
--- a/pkg/test_runner/lib/src/test_suite.dart
+++ b/pkg/test_runner/lib/src/test_suite.dart
@@ -925,8 +925,16 @@
Path(compilationTempDir).relativeTo(Repository.dir).toString();
var nullAssertions =
testFile.sharedOptions.contains('--null-assertions');
- content = dartdevcHtml(nameNoExt, nameFromModuleRootNoExt, jsDir,
- configuration.compiler, configuration.nnbdMode, nullAssertions);
+ var weakNullSafetyErrors =
+ testFile.ddcOptions.contains('--weak-null-safety-errors');
+ content = dartdevcHtml(
+ nameNoExt,
+ nameFromModuleRootNoExt,
+ jsDir,
+ configuration.compiler,
+ configuration.nnbdMode,
+ nullAssertions,
+ weakNullSafetyErrors);
}
}
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index 8118b63..269a793 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -3694,7 +3694,7 @@
alloc_object->cls()));
}
}
- if (auto create_array = alloc->AsCreateArray()) {
+ if (alloc->IsCreateArray()) {
AddSlot(slots,
Slot::GetTypeArgumentsSlotFor(
flow_graph_->thread(),
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 138d02e..b6abf76 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -1141,8 +1141,8 @@
intptr_t offset2) {
auto const address1 = RelocatedAddress(symbol1, offset1);
auto const address2 = RelocatedAddress(symbol2, offset2);
+ RELEASE_ASSERT(address1 >= address2);
auto const delta = address1 - address2;
- RELEASE_ASSERT(delta >= 0);
uleb128(delta);
}
void InitializeAbstractOrigins(intptr_t size) {
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 197e24f..8188276 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -1208,7 +1208,7 @@
ASSERT(compiler::target::kBitsPerWord == kBitsPerWord ||
Utils::IsAbsoluteUint(compiler::target::kBitsPerWord, value));
// Padding is helpful for comparing the .S with --disassemble.
- assembly_stream_->Printf("%s 0x%0.*" Px "\n", kWordDirective,
+ assembly_stream_->Printf("%s 0x%.*" Px "\n", kWordDirective,
2 * compiler::target::kWordSize, value);
return compiler::target::kWordSize;
}
@@ -1365,7 +1365,7 @@
if (end != end_of_words) {
assembly_stream_->WriteString(kSizeDirectives[kInt8SizeLog2]);
for (auto cursor = end_of_words; cursor < end; cursor++) {
- assembly_stream_->Printf("%s 0x%0.2x", cursor != end_of_words ? "," : "",
+ assembly_stream_->Printf("%s 0x%.2x", cursor != end_of_words ? "," : "",
*cursor);
}
assembly_stream_->WriteString("\n");
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index aeacffe..3f24672 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -14518,7 +14518,7 @@
if (!first_entry) {
buffer->AddString(separator);
}
- buffer->Printf("0x%0.8" Px32 ": ", it.pc_offset());
+ buffer->Printf("0x%.8" Px32 ": ", it.pc_offset());
for (intptr_t i = 0, n = it.Length(); i < n; i++) {
buffer->AddString(it.IsObject(i) ? "1" : "0");
}
@@ -24322,7 +24322,7 @@
const intptr_t length = isolate_instructions_image.build_id_length();
buffer.Printf("build_id: '");
for (intptr_t i = 0; i < length; i++) {
- buffer.Printf("%02.2x", build_id[i]);
+ buffer.Printf("%2.2x", build_id[i]);
}
buffer.Printf("'\n");
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 91a2ddc..0c40cad 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1833,8 +1833,8 @@
class KindBits : public BitField<int32_t, int8_t, kKindPos, kKindSize> {};
struct VarInfo {
- int32_t index_kind; // Bitfield for slot index on stack or in context,
- // and Entry kind of type VarInfoKind.
+ int32_t index_kind = 0; // Bitfield for slot index on stack or in context,
+ // and Entry kind of type VarInfoKind.
TokenPosition declaration_pos; // Token position of declaration.
TokenPosition begin_pos; // Token position of scope start.
TokenPosition end_pos; // Token position of scope end.
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index bac9226..f0fa4f0 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -12,27 +12,50 @@
@notNull
external bool compileTimeFlag(String flag);
-_throwNullSafetyWarningError() => throw UnsupportedError(
- 'Null safety errors cannot be shown as warnings when running with sound '
- 'null safety.');
+_throwInvalidFlagError(String message) =>
+ throw UnsupportedError('Invalid flag combination.\n$message');
@notNull
bool _weakNullSafetyWarnings = false;
-/// Sets the runtime mode to show warnings when running with weak null safety.
+/// Sets the runtime mode to show warnings when types violate sound null safety.
///
-/// These are warnings for issues that will become errors when sound null safety
-/// is enabled. Showing warnings while running with sound null safety is not
-/// supported (they will be errors).
+/// This option is not compatible with weak null safety errors or sound null
+/// safety (the warnings will be errors).
void weakNullSafetyWarnings(bool showWarnings) {
if (showWarnings && compileTimeFlag('soundNullSafety')) {
- _throwNullSafetyWarningError();
+ _throwInvalidFlagError(
+ 'Null safety violations cannot be shown as warnings when running with '
+ 'sound null safety.');
}
_weakNullSafetyWarnings = showWarnings;
}
@notNull
+bool _weakNullSafetyErrors = false;
+
+/// Sets the runtime mode to throw errors when types violate sound null safety.
+///
+/// This option is not compatible with weak null safety warnings (the warnings
+/// are now errors) or sound null safety (the errors are already errors).
+void weakNullSafetyErrors(bool showErrors) {
+ if (showErrors && compileTimeFlag('soundNullSafety')) {
+ _throwInvalidFlagError(
+ 'Null safety violations are already thrown as errors when running with '
+ 'sound null safety.');
+ }
+
+ if (showErrors && _weakNullSafetyWarnings) {
+ _throwInvalidFlagError(
+ 'Null safety violations can be shown as warnings or thrown as errors, '
+ 'not both.');
+ }
+
+ _weakNullSafetyErrors = showErrors;
+}
+
+@notNull
bool _nonNullAsserts = false;
/// Sets the runtime mode to insert non-null assertions on non-nullable method
@@ -250,10 +273,12 @@
JS('void', 'console.warn(#)', arg);
}
-void _nullWarn(arg) {
+void _nullWarn(message) {
if (_weakNullSafetyWarnings) {
- _warn('$arg\n'
+ _warn('$message\n'
'This will become a failure when runtime null safety is enabled.');
+ } else if (_weakNullSafetyErrors) {
+ throw TypeErrorImpl(message);
}
}
diff --git a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
index 79b69ee..7f66713 100644
--- a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
+++ b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
@@ -2,3 +2,5 @@
# make it easer to depend on libraries.dart from sdk packages like dart2js.
name: sdk_library_metadata
publish_to: none
+environment:
+ sdk: '>=2.11.0 <3.0.0'
diff --git a/tests/dartdevc/weak_null_safety_errors_test.dart b/tests/dartdevc/weak_null_safety_errors_test.dart
new file mode 100644
index 0000000..b6663e9
--- /dev/null
+++ b/tests/dartdevc/weak_null_safety_errors_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Requirements=nnbd-weak
+
+// dartdevcOptions=--weak-null-safety-errors
+
+import 'package:expect/expect.dart';
+
+void main() {
+ Expect.throwsTypeError(() => null as int);
+ dynamic dynamicNull = null;
+ Expect.throwsTypeError(() => fn(dynamicNull));
+}
+
+void fn(StringBuffer arg) {}
diff --git a/tests/standalone/standalone_kernel.status b/tests/standalone/standalone_kernel.status
index 63813b2..47d354b 100644
--- a/tests/standalone/standalone_kernel.status
+++ b/tests/standalone/standalone_kernel.status
@@ -109,3 +109,6 @@
[ $builder_tag == crossword || $compiler != dartk && $compiler != dartkp || $compiler == dartkp && $system == windows ]
entrypoints_verification_test: SkipByDesign # Requires VM to run. Cannot run in precompiled Windows because the DLL is linked against dart.exe instead of dart_precompiled_runtime.exe. Cannot run in cross-word environment as native extension is not built.
+
+[ $compiler != dartk || $runtime != vm ]
+check_for_aot_snapshot_jit_test: SkipByDesign # Test relies on paths, requires JIT test environment.
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index 52e78e2..5a07018 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -110,3 +110,6 @@
[ $builder_tag == crossword || $compiler != dartk && $compiler != dartkp || $compiler == dartkp && $system == windows ]
entrypoints_verification_test: SkipByDesign # Requires VM to run. Cannot run in precompiled Windows because the DLL is linked against dart.exe instead of dart_precompiled_runtime.exe. Cannot run in cross-word environment as native extension is not built.
+
+[ $compiler != dartk || $runtime != vm ]
+check_for_aot_snapshot_jit_test: SkipByDesign # Test relies on paths, requires JIT test environment.
diff --git a/tools/VERSION b/tools/VERSION
index 6296136..ccc77af 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 50
+PRERELEASE 51
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/generate_package_config.dart b/tools/generate_package_config.dart
index 24c69c2..9369cce 100644
--- a/tools/generate_package_config.dart
+++ b/tools/generate_package_config.dart
@@ -98,8 +98,7 @@
.toUri(p.relative(packageDir, from: p.dirname(configFilePath)))
.toString(),
if (hasLibDirectory) 'packageUri': 'lib/',
- if (version != null)
- 'languageVersion': '${version.major}.${version.minor}'
+ 'languageVersion': '${version.major}.${version.minor}'
};
}
}
@@ -153,18 +152,29 @@
/// Returns `null` if there is no pubspec or no SDK constraint.
Version pubspecLanguageVersion(String packageDir) {
var pubspecFile = File(p.join(packageDir, 'pubspec.yaml'));
+ var relative = p.relative(packageDir, from: repoRoot);
- if (!pubspecFile.existsSync()) return null;
+ if (!pubspecFile.existsSync()) {
+ print("Error: Missing pubspec for $relative.");
+ exit(1);
+ }
var pubspec =
loadYaml(pubspecFile.readAsStringSync()) as Map<dynamic, dynamic>;
- if (!pubspec.containsKey('environment')) return null;
+ if (!pubspec.containsKey('environment')) {
+ print("Error: Pubspec for $relative has no SDK constraint.");
+ exit(1);
+ }
var environment = pubspec['environment'] as Map<dynamic, dynamic>;
- if (!environment.containsKey('sdk')) return null;
+ if (!environment.containsKey('sdk')) {
+ print("Error: Pubspec for $relative has no SDK constraint.");
+ exit(1);
+ }
var sdkConstraint = VersionConstraint.parse(environment['sdk'] as String);
if (sdkConstraint is VersionRange) return sdkConstraint.min;
- return null;
+ print("Error: SDK constraint $relative is not a version range.");
+ exit(1);
}