Version 2.13.0-210.0.dev Merge commit 'a38a2dd34385f7e9711b0efdcd4558e45590b07c' into 'dev'
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_packet_transformer.dart b/pkg/analysis_server/lib/src/lsp/lsp_packet_transformer.dart index b80e082..27c652b 100644 --- a/pkg/analysis_server/lib/src/lsp/lsp_packet_transformer.dart +++ b/pkg/analysis_server/lib/src/lsp/lsp_packet_transformer.dart
@@ -2,11 +2,12 @@ // 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.9 - import 'dart:async'; import 'dart:convert'; +import 'package:analysis_server/src/utilities/stream.dart'; +import 'package:collection/collection.dart'; + class InvalidEncodingError { final String headers; InvalidEncodingError(this.headers); @@ -19,7 +20,7 @@ class LspHeaders { final String rawHeaders; final int contentLength; - final String encoding; + final String? encoding; LspHeaders(this.rawHeaders, this.contentLength, this.encoding); } @@ -35,44 +36,46 @@ class LspPacketTransformer extends StreamTransformerBase<List<int>, String> { @override Stream<String> bind(Stream<List<int>> stream) { - StreamSubscription<int> input; - StreamController<String> _output; + LspHeaders? headersState; final buffer = <int>[]; - var isParsingHeaders = true; - LspHeaders headers; - _output = StreamController<String>( - onListen: () { - input = stream.expand((b) => b).listen( + var controller = MoreTypedStreamController<String, + _LspPacketTransformerListenData, _LspPacketTransformerPauseData>( + onListen: (controller) { + var input = stream.expand((b) => b).listen( (codeUnit) { buffer.add(codeUnit); - if (isParsingHeaders && _endsWithCrLfCrLf(buffer)) { - headers = _parseHeaders(buffer); + var headers = headersState; + if (headers == null && _endsWithCrLfCrLf(buffer)) { + headersState = _parseHeaders(buffer); buffer.clear(); - isParsingHeaders = false; - } else if (!isParsingHeaders && + } else if (headers != null && buffer.length >= headers.contentLength) { // UTF-8 is the default - and only supported - encoding for LSP. // The string 'utf8' is valid since it was published in the original spec. // Any other encodings should be rejected with an error. if ([null, 'utf-8', 'utf8'] .contains(headers.encoding?.toLowerCase())) { - _output.add(utf8.decode(buffer)); + controller.add(utf8.decode(buffer)); } else { - _output.addError(InvalidEncodingError(headers.rawHeaders)); + controller.addError(InvalidEncodingError(headers.rawHeaders)); } buffer.clear(); - isParsingHeaders = true; + headersState = null; } }, - onError: _output.addError, - onDone: _output.close, + onError: controller.addError, + onDone: controller.close, ); + return _LspPacketTransformerListenData(input); }, - onPause: () => input.pause(), - onResume: () => input.resume(), - onCancel: () => input.cancel(), + onPause: (listenData) { + listenData.input.pause(); + return _LspPacketTransformerPauseData(); + }, + onResume: (listenData, pauseData) => listenData.input.resume(), + onCancel: (listenData) => listenData.input.cancel(), ); - return _output.stream; + return controller.controller.stream; } /// Whether [buffer] ends in '\r\n\r\n'. @@ -85,13 +88,13 @@ buffer[l - 4] == 13; } - static String _extractEncoding(String header) { + static String? _extractEncoding(String? header) { final charset = header ?.split(';') - ?.map((s) => s.trim().toLowerCase()) - ?.firstWhere((s) => s.startsWith('charset='), orElse: () => null); + .map((s) => s.trim().toLowerCase()) + .firstWhereOrNull((s) => s.startsWith('charset=')); - return charset == null ? null : charset.split('=')[1]; + return charset?.split('=')[1]; } /// Decodes [buffer] into a String and returns the 'Content-Length' header value. @@ -102,9 +105,19 @@ final lengthHeader = headers.firstWhere((h) => h.startsWith('Content-Length')); final length = lengthHeader.split(':').last.trim(); - final contentTypeHeader = headers - .firstWhere((h) => h.startsWith('Content-Type'), orElse: () => null); + final contentTypeHeader = + headers.firstWhereOrNull((h) => h.startsWith('Content-Type')); final encoding = _extractEncoding(contentTypeHeader); return LspHeaders(asString, int.parse(length), encoding); } } + +/// The data class for [StreamController.onListen]. +class _LspPacketTransformerListenData { + final StreamSubscription<int> input; + + _LspPacketTransformerListenData(this.input); +} + +/// The marker class for [StreamController.onPause]. +class _LspPacketTransformerPauseData {}
diff --git a/pkg/analysis_server/lib/src/status/ast_writer.dart b/pkg/analysis_server/lib/src/status/ast_writer.dart index ef6cc8e..d3917ce 100644 --- a/pkg/analysis_server/lib/src/status/ast_writer.dart +++ b/pkg/analysis_server/lib/src/status/ast_writer.dart
@@ -2,10 +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. -// @dart = 2.9 - -import 'dart:collection'; - import 'package:analysis_server/src/status/tree_writer.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; @@ -13,11 +9,12 @@ /// A visitor that will produce an HTML representation of an AST structure. class AstWriter extends UnifyingAstVisitor with TreeWriter { + @override + final StringBuffer buffer; + /// Initialize a newly created element writer to write the HTML representation /// of visited nodes on the given [buffer]. - AstWriter(StringBuffer buffer) { - this.buffer = buffer; - } + AstWriter(this.buffer); @override void visitNode(AstNode node) { @@ -33,8 +30,8 @@ /// Write a representation of the properties of the given [node] to the /// buffer. - Map<String, Object> _computeProperties(AstNode node) { - Map<String, Object> properties = HashMap<String, Object>(); + Map<String, Object?> _computeProperties(AstNode node) { + var properties = <String, Object?>{}; properties['name'] = _getName(node); if (node is ArgumentListImpl) { @@ -150,26 +147,24 @@ /// Return the name of the given [node], or `null` if the given node is not a /// declaration. - String _getName(AstNode node) { + String? _getName(AstNode node) { if (node is ClassTypeAlias) { return node.name.name; } else if (node is ClassDeclaration) { return node.name.name; } else if (node is ConstructorDeclaration) { - if (node.name == null) { + var name = node.name; + if (name == null) { return node.returnType.name; } else { - return node.returnType.name + '.' + node.name.name; + return node.returnType.name + '.' + name.name; } } else if (node is ConstructorName) { return node.toSource(); } else if (node is FieldDeclaration) { return _getNames(node.fields); } else if (node is FunctionDeclaration) { - var nameNode = node.name; - if (nameNode != null) { - return nameNode.name; - } + return node.name.name; } else if (node is FunctionTypeAlias) { return node.name.name; } else if (node is Identifier) {
diff --git a/pkg/analysis_server/lib/src/status/element_writer.dart b/pkg/analysis_server/lib/src/status/element_writer.dart index e75777c..dffcd49 100644 --- a/pkg/analysis_server/lib/src/status/element_writer.dart +++ b/pkg/analysis_server/lib/src/status/element_writer.dart
@@ -2,9 +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. -// @dart = 2.9 - -import 'dart:collection'; import 'dart:convert'; import 'package:analysis_server/src/status/tree_writer.dart'; @@ -14,11 +11,12 @@ /// A visitor that will produce an HTML representation of an element structure. class ElementWriter extends GeneralizingElementVisitor with TreeWriter { + @override + final StringBuffer buffer; + /// Initialize a newly created element writer to write the HTML representation /// of visited elements on the given [buffer]. - ElementWriter(StringBuffer buffer) { - this.buffer = buffer; - } + ElementWriter(this.buffer); @override void visitElement(Element element) { @@ -34,8 +32,8 @@ /// Write a representation of the properties of the given [node] to the /// buffer. - Map<String, Object> _computeProperties(Element element) { - Map<String, Object> properties = HashMap<String, Object>(); + Map<String, Object?> _computeProperties(Element element) { + var properties = <String, Object?>{}; properties['metadata'] = element.metadata; properties['nameOffset'] = element.nameOffset;
diff --git a/pkg/analysis_server/lib/src/status/pages.dart b/pkg/analysis_server/lib/src/status/pages.dart index 2edec799..61f4704 100644 --- a/pkg/analysis_server/lib/src/status/pages.dart +++ b/pkg/analysis_server/lib/src/status/pages.dart
@@ -2,8 +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. -// @dart = 2.9 - import 'dart:convert'; import 'dart:io'; @@ -11,7 +9,7 @@ final NumberFormat numberFormat = NumberFormat.decimalPattern(); -String escape(String text) => text == null ? '' : htmlEscape.convert(text); +String escape(String? text) => text == null ? '' : htmlEscape.convert(text); String printInteger(int value) => numberFormat.format(value); @@ -26,13 +24,13 @@ final String id; final String title; - final String description; + final String? description; Page(this.id, this.title, {this.description}); String get path => '/$id'; - Future<void> asyncDiv(void Function() gen, {String classes}) async { + Future<void> asyncDiv(void Function() gen, {String? classes}) async { if (classes != null) { buf.writeln('<div class="$classes">'); } else { @@ -48,7 +46,7 @@ div(() => buf.writeln(str), classes: 'blankslate'); } - void div(void Function() gen, {String classes}) { + void div(void Function() gen, {String? classes}) { if (classes != null) { buf.writeln('<div class="$classes">'); } else { @@ -68,7 +66,7 @@ Future<void> generatePage(Map<String, String> params); - void h1(String text, {String classes}) { + void h1(String text, {String? classes}) { if (classes != null) { buf.writeln('<h1 class="$classes">${escape(text)}</h1>'); } else { @@ -100,7 +98,7 @@ bool isCurrentPage(String pathToTest) => path == pathToTest; - void p(String text, {String style, bool raw = false, String classes}) { + void p(String text, {String? style, bool raw = false, String? classes}) { var c = classes == null ? '' : ' class="$classes"'; if (style != null) { @@ -110,7 +108,7 @@ } } - void pre(void Function() gen, {String classes}) { + void pre(void Function() gen, {String? classes}) { if (classes != null) { buf.write('<pre class="$classes">'); } else { @@ -127,7 +125,7 @@ }); } - void ul<T>(Iterable<T> items, void Function(T item) gen, {String classes}) { + void ul<T>(Iterable<T> items, void Function(T item) gen, {String? classes}) { buf.writeln('<ul${classes == null ? '' : ' class=$classes'}>'); for (var item in items) { buf.write('<li>'); @@ -213,7 +211,7 @@ HttpRequest request, { int code = HttpStatus.ok, }) async { - if (request.headers.contentType.subType == 'json') { + if (request.headers.contentType?.subType == 'json') { return respondJson(request, {'success': true}, code); }
diff --git a/pkg/analysis_server/lib/src/status/tree_writer.dart b/pkg/analysis_server/lib/src/status/tree_writer.dart index 25bd024..ec20780 100644 --- a/pkg/analysis_server/lib/src/status/tree_writer.dart +++ b/pkg/analysis_server/lib/src/status/tree_writer.dart
@@ -2,8 +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. -// @dart = 2.9 - import 'dart:convert'; import 'package:analyzer/exception/exception.dart'; @@ -13,9 +11,6 @@ /// Utility methods that can be mixed in to classes that produce an HTML /// representation of a tree structure. mixin TreeWriter { - /// The buffer on which the HTML is to be written. - StringBuffer buffer; - /// The current level of indentation. int indentLevel = 0; @@ -23,6 +18,9 @@ /// write out the tree structure. List<CaughtException> exceptions = <CaughtException>[]; + /// The buffer on which the HTML is to be written. + StringBuffer get buffer; + void indent([int extra = 0]) { for (var i = 0; i < indentLevel; i++) { buffer.write('┊ '); @@ -36,7 +34,7 @@ } /// Write a representation of the given [properties] to the buffer. - void writeProperties(Map<String, Object> properties) { + void writeProperties(Map<String, Object?> properties) { var propertyNames = properties.keys.toList(); propertyNames.sort(); for (var propertyName in propertyNames) { @@ -45,7 +43,7 @@ } /// Write the [value] of the property with the given [name]. - void writeProperty(String name, Object value) { + void writeProperty(String name, Object? value) { if (value != null) { indent(2); buffer.write('$name = '); @@ -54,7 +52,7 @@ } } - String _toString(Object value) { + String? _toString(Object? value) { try { if (value is Source) { return 'Source (uri="${value.uri}", path="${value.fullName}")';
diff --git a/pkg/analysis_server/lib/src/utilities/stream.dart b/pkg/analysis_server/lib/src/utilities/stream.dart new file mode 100644 index 0000000..5ac8669 --- /dev/null +++ b/pkg/analysis_server/lib/src/utilities/stream.dart
@@ -0,0 +1,61 @@ +// Copyright (c) 2021, 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'; + +class MoreTypedStreamController<T, ListenData, PauseData> { + final StreamController<T> controller; + + /// A wrapper around [StreamController] that statically guarantees its + /// clients that [onPause] and [onCancel] can only be invoked after + /// [onListen], and [onResume] can only be invoked after [onPause]. + /// + /// There is no static guarantee that [onPause] will not be invoked twice. + /// + /// Internally the wrapper is not safe, and uses explicit null checks. + factory MoreTypedStreamController({ + required ListenData Function(StreamController<T>) onListen, + PauseData Function(ListenData)? onPause, + void Function(ListenData, PauseData)? onResume, + FutureOr<void> Function(ListenData)? onCancel, + bool sync = false, + }) { + ListenData? listenData; + PauseData? pauseData; + var controller = StreamController<T>( + onPause: () { + if (pauseData != null) { + throw StateError('Already paused'); + } + var local_onPause = onPause; + if (local_onPause != null) { + pauseData = local_onPause(listenData!); + } + }, + onResume: () { + var local_onResume = onResume; + if (local_onResume != null) { + var local_pauseData = pauseData!; + pauseData = null; + local_onResume(listenData!, local_pauseData); + } + }, + onCancel: () { + var local_onCancel = onCancel; + if (local_onCancel != null) { + var local_listenData = listenData!; + listenData = null; + local_onCancel(local_listenData); + } + }, + sync: sync, + ); + controller.onListen = () { + listenData = onListen(controller); + }; + return MoreTypedStreamController._(controller); + } + + MoreTypedStreamController._(this.controller); +}
diff --git a/pkg/analysis_server/test/integration/lsp_server/diagnostic_test.dart b/pkg/analysis_server/test/integration/lsp_server/diagnostic_test.dart index 7f9a527..6b026f7 100644 --- a/pkg/analysis_server/test/integration/lsp_server/diagnostic_test.dart +++ b/pkg/analysis_server/test/integration/lsp_server/diagnostic_test.dart
@@ -17,6 +17,34 @@ @reflectiveTest class DiagnosticTest extends AbstractLspAnalysisServerIntegrationTest { + Future<void> test_contextMessage() async { + const content = ''' +void f() { + x = 0; + int [[x]] = 1; + print(x); +} +'''; + newFile(mainFilePath, content: withoutMarkers(content)); + + final diagnosticsUpdate = waitForDiagnostics(mainFileUri); + await initialize(); + final diagnostics = await diagnosticsUpdate; + + expect(diagnostics, hasLength(1)); + final diagnostic = diagnostics.first; + expect( + diagnostic.message, + startsWith( + "Local variable 'x' can't be referenced before it is declared")); + + expect(diagnostic.relatedInformation, hasLength(1)); + final relatedInfo = diagnostic.relatedInformation.first; + expect(relatedInfo.message, equals("The declaration of 'x' is here.")); + expect(relatedInfo.location.uri, equals('$mainFileUri')); + expect(relatedInfo.location.range, equals(rangeFromMarkers(content))); + } + Future<void> test_initialAnalysis() async { newFile(mainFilePath, content: 'String a = 1;');
diff --git a/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart b/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart index bb8927a..d25328e 100644 --- a/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart +++ b/pkg/analysis_server/test/src/lsp/lsp_packet_transformer_test.dart
@@ -2,8 +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. -// @dart = 2.9 - import 'dart:convert'; import 'package:analysis_server/src/lsp/lsp_packet_transformer.dart'; @@ -85,7 +83,7 @@ }); } -List<int> makeLspPacket(String json, [String contentType]) { +List<int> makeLspPacket(String json, [String? contentType]) { final utf8EncodedBody = utf8.encode(json); final header = 'Content-Length: ${utf8EncodedBody.length}' + (contentType != null ? '\r\nContent-Type: $contentType' : '') +
diff --git a/pkg/analysis_server/test/src/lsp/test_all.dart b/pkg/analysis_server/test/src/lsp/test_all.dart index e51799f..5f61e61 100644 --- a/pkg/analysis_server/test/src/lsp/test_all.dart +++ b/pkg/analysis_server/test/src/lsp/test_all.dart
@@ -2,8 +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. -// @dart = 2.9 - import 'package:test_reflective_loader/test_reflective_loader.dart'; import 'lsp_packet_transformer_test.dart' as lsp_packet_transformer;
diff --git a/pkg/analysis_server/test/src/server/test_all.dart b/pkg/analysis_server/test/src/server/test_all.dart index 4dcbb2a..cf5da10 100644 --- a/pkg/analysis_server/test/src/server/test_all.dart +++ b/pkg/analysis_server/test/src/server/test_all.dart
@@ -2,8 +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. -// @dart = 2.9 - import 'sdk_configuration_test.dart' as sdk_configuration; void main() {
diff --git a/pkg/analysis_server/test/src/services/completion/filtering/test_all.dart b/pkg/analysis_server/test/src/services/completion/filtering/test_all.dart index 77a55cd..ffc9b80 100644 --- a/pkg/analysis_server/test/src/services/completion/filtering/test_all.dart +++ b/pkg/analysis_server/test/src/services/completion/filtering/test_all.dart
@@ -2,8 +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. -// @dart = 2.9 - import 'package:test_reflective_loader/test_reflective_loader.dart'; import 'fuzzy_matcher_test.dart' as fuzzy_matcher;
diff --git a/pkg/dartdev/lib/src/templates/web_simple.dart b/pkg/dartdev/lib/src/templates/web_simple.dart index 0fd6c34..12ed1ce 100644 --- a/pkg/dartdev/lib/src/templates/web_simple.dart +++ b/pkg/dartdev/lib/src/templates/web_simple.dart
@@ -31,7 +31,7 @@ # homepage: https://www.example.com environment: - sdk: '>=2.10.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' # dependencies: # path: ^1.7.0 @@ -72,7 +72,7 @@ import 'dart:html'; void main() { - querySelector('#output').text = 'Your Dart app is running.'; + querySelector('#output')?.text = 'Your Dart app is running.'; } ''';
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart index 25f75c3..1dceafe 100644 --- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart +++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
@@ -256,6 +256,12 @@ /// Depends on SDK artifacts (such as the sound and unsound dart_sdk.js /// files) generated from the 'dartdevc_test' target. Future<void> initSource(SetupCompilerOptions setup, String source) async { + // Perform setup sanity checks. + var summaryPath = setup.options.sdkSummary.toFilePath(); + if (!File(summaryPath).existsSync()) { + throw StateError('Unable to find SDK summary at path: $summaryPath.'); + } + // Prepend Dart nullability comment. source = '${setup.dartLangComment}\n\n$source'; this.setup = setup;
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc index e84949f..4eddc2e 100644 --- a/runtime/vm/compiler/aot/precompiler.cc +++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -144,6 +144,8 @@ static constexpr const char* kLocalParent = "parent of a local function"; // The object has an entry point pragma that requires it be retained. static constexpr const char* kEntryPointPragma = "entry point pragma"; + // The function is a target of FFI callback. + static constexpr const char* kFfiCallbackTarget = "ffi callback target"; }; class RetainedReasonsWriter : public ValueObject { @@ -935,6 +937,13 @@ // Local closure function. const auto& target = Function::Cast(entry); AddFunction(target, RetainReasons::kLocalClosure); + if (target.IsFfiTrampoline()) { + const auto& callback_target = + Function::Handle(Z, target.FfiCallbackTarget()); + if (!callback_target.IsNull()) { + AddFunction(callback_target, RetainReasons::kFfiCallbackTarget); + } + } } else if (entry.IsCode()) { const auto& target_code = Code::Cast(entry); if (target_code.IsAllocationStubCode()) {
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart index 0e918db..ab2ecf5 100644 --- a/sdk/lib/io/socket.dart +++ b/sdk/lib/io/socket.dart
@@ -154,7 +154,7 @@ /// Looks up the addresses of a host. /// - /// If [type] is [InternetAddressType.ANY], it will lookup both + /// If [type] is [InternetAddressType.any], it will lookup both /// IP version 4 (IPv4) and IP version 6 (IPv6) addresses. /// If [type] is either [InternetAddressType.IPv4] or /// [InternetAddressType.IPv6] it will only lookup addresses of the
diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart index 11baff6..e9a853c 100644 --- a/tests/ffi/function_callbacks_test.dart +++ b/tests/ffi/function_callbacks_test.dart
@@ -13,6 +13,7 @@ // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code --stacktrace-every=100 // VMOptions=--use-bare-instructions=false +// VMOptions=--enable-testing-pragmas --dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects // SharedObjects=ffi_test_functions import 'dart:ffi';
diff --git a/tests/ffi_2/function_callbacks_test.dart b/tests/ffi_2/function_callbacks_test.dart index 11baff6..e9a853c 100644 --- a/tests/ffi_2/function_callbacks_test.dart +++ b/tests/ffi_2/function_callbacks_test.dart
@@ -13,6 +13,7 @@ // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code --stacktrace-every=100 // VMOptions=--use-bare-instructions=false +// VMOptions=--enable-testing-pragmas --dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects // SharedObjects=ffi_test_functions import 'dart:ffi';
diff --git a/tools/VERSION b/tools/VERSION index 240c7a8..e5962f7d 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -27,5 +27,5 @@ MAJOR 2 MINOR 13 PATCH 0 -PRERELEASE 209 +PRERELEASE 210 PRERELEASE_PATCH 0 \ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json index 8527b24..9d6d61a 100644 --- a/tools/bots/test_matrix.json +++ b/tools/bots/test_matrix.json
@@ -3456,7 +3456,8 @@ "name": "build dart", "script": "tools/build.py", "arguments": [ - "create_sdk" + "create_sdk", + "dartdevc_test" ] }, {