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 2edec79..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"
]
},
{