Version 3.11.0-70.0.dev
Merge 294b05898f5edf8dd0aaedf51e48778dd59c631e into dev
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index bbbdfb9..b041a07 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -146,6 +146,14 @@
ldflags += [
"-rpath",
"buildtools/mac-$host_cpu/clang/lib/clang/22/lib/darwin",
+
+ # Back from xcodebuild/ReleaseTSAN/dart
+ "-rpath",
+ "@loader_path/../../buildtools/mac-$host_cpu/clang/lib/clang/22/lib/darwin",
+
+ # Back from xcodebuild/ReleaseTSAN/dart-sdk/bin/dart
+ "-rpath",
+ "@loader_path/../../../../buildtools/mac-$host_cpu/clang/lib/clang/22/lib/darwin",
]
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
index a7b1149..0744c20 100644
--- a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
@@ -187,6 +187,11 @@
}
@override
+ bool visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+ return _elementExits(node.propertyName.element);
+ }
+
+ @override
bool visitEmptyStatement(EmptyStatement node) => false;
@override
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 1448ac9..cccf3cc 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -4315,16 +4315,22 @@
int mixinIndex,
NamedTypeImpl mixinName,
) {
+ var enclosingClass = _enclosingClass!;
var mixinType = mixinName.type as InterfaceTypeImpl;
for (var constraint in mixinType.superclassConstraints) {
- var superType = _enclosingClass!.supertype as InterfaceTypeImpl;
+ var superType = enclosingClass.supertype as InterfaceTypeImpl;
superType = superType.withNullability(NullabilitySuffix.none);
bool isSatisfied = typeSystem.isSubtypeOf(superType, constraint);
if (!isSatisfied) {
for (int i = 0; i < mixinIndex && !isSatisfied; i++) {
+ // If there are less mixin types than mixin nodes, escape.
+ if (i >= enclosingClass.mixins.length) {
+ return false;
+ }
+ // Probe a previous mixin type.
isSatisfied = typeSystem.isSubtypeOf(
- _enclosingClass!.mixins[i],
+ enclosingClass.mixins[i],
constraint,
);
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index c647931..daf8a4b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -5178,11 +5178,12 @@
return;
}
- nameScope = FormalParameterScope(
- TypeParameterScope(nameScope, element.typeParameters),
- element.formalParameters,
- );
- super.visitFunctionExpression(node);
+ nameScope = TypeParameterScope(nameScope, element.typeParameters);
+ node.typeParameters?.accept(this);
+ node.parameters?.accept(this);
+
+ nameScope = FormalParameterScope(nameScope, element.formalParameters);
+ node.body.accept(this);
} finally {
nameScope = outerScope;
_enclosingClosure = outerClosure;
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index f085ec3..7696841 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -75167,6 +75167,47 @@
);
}
+ test_manifest_constInitializer_functionExpression_formalParameter_defaultValue_formalParameter() async {
+ await _runLibraryManifestScenario(
+ initialCode: r'''
+final f = ({int x = x}) {};
+''',
+ expectedInitialEvents: r'''
+[operation] linkLibraryCycle SDK
+[operation] linkLibraryCycle
+ package:test/test.dart
+ hashForRequirements: #H0
+ declaredGetters
+ f: #M0
+ declaredVariables
+ f: #M1
+ exportMapId: #M2
+ exportMap
+ f: #M0
+''',
+ updatedCode: r'''
+final f = ({int x = x}) {};
+class A {}
+''',
+ expectedUpdatedEvents: r'''
+[operation] linkLibraryCycle
+ package:test/test.dart
+ hashForRequirements: #H1
+ declaredClasses
+ A: #M3
+ interface: #M4
+ declaredGetters
+ f: #M0
+ declaredVariables
+ f: #M1
+ exportMapId: #M5
+ exportMap
+ A: #M3
+ f: #M0
+''',
+ );
+ }
+
test_manifest_constInitializer_identifier_addIdentifier() async {
configuration.withElementManifests = true;
await _runLibraryManifestScenario(
diff --git a/pkg/analyzer/test/src/dart/resolution/function_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/function_expression_test.dart
index 95ea7e3..b51e4d7 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_expression_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'context_collection_resolution.dart';
@@ -95,4 +96,40 @@
staticType: Null Function<T extends num>()
''');
}
+
+ test_signatureScope_noFormalParameters() async {
+ await assertErrorsInCode(
+ '''
+var f = ({int x = x}) {};
+''',
+ [error(CompileTimeErrorCode.undefinedIdentifier, 18, 1)],
+ );
+
+ var node = findNode.singleFormalParameterList;
+ assertResolvedNodeText(node, r'''
+FormalParameterList
+ leftParenthesis: (
+ leftDelimiter: {
+ parameter: DefaultFormalParameter
+ parameter: SimpleFormalParameter
+ type: NamedType
+ name: int
+ element: dart:core::@class::int
+ type: int
+ name: x
+ declaredElement: <testLibraryFragment> x@14
+ element: isPublic
+ type: int
+ separator: =
+ defaultValue: SimpleIdentifier
+ token: x
+ element: <null>
+ staticType: InvalidType
+ declaredElement: <testLibraryFragment> x@14
+ element: isPublic
+ type: int
+ rightDelimiter: }
+ rightParenthesis: )
+''');
+ }
}
diff --git a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
index f3257bd..41715a1 100644
--- a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
+++ b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
@@ -1027,6 +1027,28 @@
''', 0);
}
+ test_dotShorthandPropertyAccess_getterReturnsNever() async {
+ await _assertNthStatementExits(r'''
+class C {
+ static Never get foo => throw 42;
+}
+void f() {
+ C _ = .foo;
+}
+''', 0);
+ }
+
+ test_dotShorthandPropertyAccess_noExit() async {
+ await _assertNthStatementDoesNotExit(r'''
+class C {
+ static C get foo => C();
+}
+void f() {
+ C _ = .foo;
+}
+''', 0);
+ }
+
test_forStatement_implicitTrue_breakWithLabel() async {
await _assertNthStatementDoesNotExit(r'''
void f() {
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart
index 07262bb..58356cc 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart
@@ -16,6 +16,23 @@
@reflectiveTest
class MixinApplicationNotImplementedInterfaceTest
extends PubPackageResolutionTest {
+ test_class_hasRecursion() async {
+ // https://github.com/dart-lang/sdk/issues/61829
+ await assertErrorsInCode(
+ '''
+class A {}
+abstract class X with Unresolved, M, CycleWithX {}
+mixin M on A {}
+mixin CycleWithX on X {}
+''',
+ [
+ error(CompileTimeErrorCode.recursiveInterfaceInheritance, 26, 1),
+ error(CompileTimeErrorCode.mixinOfNonClass, 33, 10),
+ error(CompileTimeErrorCode.recursiveInterfaceInheritance, 84, 10),
+ ],
+ );
+ }
+
test_class_matchingInterface() async {
await assertNoErrorsInCode('''
abstract class A<T> {}
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 1ac621b8..a396cea 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -25,13 +25,11 @@
String prettyPrint(
Node node, {
bool enableMinification = false,
- bool allowVariableMinification = true,
bool preferSemicolonToNewlineInMinifiedOutput = false,
}) {
// TODO(johnniwinther): Do we need all the options here?
JavaScriptPrintingOptions options = JavaScriptPrintingOptions(
- shouldCompressOutput: enableMinification,
- minifyLocalVariables: allowVariableMinification,
+ minify: enableMinification,
preferSemicolonToNewlineInMinifiedOutput:
preferSemicolonToNewlineInMinifiedOutput,
);
@@ -48,13 +46,12 @@
DumpInfoJsAstRegistry? monitor,
JavaScriptAnnotationMonitor annotationMonitor =
const JavaScriptAnnotationMonitor(),
- bool allowVariableMinification = true,
List<CodeOutputListener> listeners = const [],
}) {
+ bool enableMinification = compilerOptions.enableMinification;
JavaScriptPrintingOptions options = JavaScriptPrintingOptions(
utf8: compilerOptions.features.writeUtf8.isEnabled,
- shouldCompressOutput: compilerOptions.enableMinification,
- minifyLocalVariables: allowVariableMinification,
+ minify: enableMinification,
);
CodeBuffer outBuffer = CodeBuffer(listeners);
SourceInformationProcessor sourceInformationProcessor =
diff --git a/pkg/compiler/lib/src/js/js_debug.dart b/pkg/compiler/lib/src/js/js_debug.dart
index b45179c..09f3035 100644
--- a/pkg/compiler/lib/src/js/js_debug.dart
+++ b/pkg/compiler/lib/src/js/js_debug.dart
@@ -12,8 +12,7 @@
/// Unparse the JavaScript [node].
String nodeToString(Node node, {bool pretty = false}) {
JavaScriptPrintingOptions options = JavaScriptPrintingOptions(
- shouldCompressOutput: !pretty,
- preferSemicolonToNewlineInMinifiedOutput: !pretty,
+ minify: !pretty,
);
LenientPrintingContext printingContext = LenientPrintingContext();
Printer(options, printingContext).visit(node);
diff --git a/pkg/compiler/test/js/js_parser_statements_test.dart b/pkg/compiler/test/js/js_parser_statements_test.dart
index d69f6a4..1fc0d3f 100644
--- a/pkg/compiler/test/js/js_parser_statements_test.dart
+++ b/pkg/compiler/test/js/js_parser_statements_test.dart
@@ -9,7 +9,7 @@
testStatement(String statement, arguments, String expect) {
jsAst.Node node = js.statement(statement, arguments);
- String jsText = jsAst.prettyPrint(node, allowVariableMinification: false);
+ String jsText = jsAst.prettyPrint(node);
Expect.stringEquals(
expect.trim(),
jsText.trim(),
diff --git a/pkg/compiler/test/js/js_parser_test.dart b/pkg/compiler/test/js/js_parser_test.dart
index 0757adc..70aa7c0 100644
--- a/pkg/compiler/test/js/js_parser_test.dart
+++ b/pkg/compiler/test/js/js_parser_test.dart
@@ -8,7 +8,7 @@
testExpression(String expression, [String expect = ""]) {
jsAst.Node node = js(expression);
- String jsText = jsAst.prettyPrint(node, allowVariableMinification: false);
+ String jsText = jsAst.prettyPrint(node);
if (expect == "") {
Expect.stringEquals(expression, jsText);
} else {
diff --git a/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart b/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart
index c5e257b..67ccc09 100644
--- a/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart
+++ b/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart
@@ -696,7 +696,7 @@
String nodeToString(js.Node node) {
js.JavaScriptPrintingOptions options = js.JavaScriptPrintingOptions(
- shouldCompressOutput: true,
+ minify: true,
preferSemicolonToNewlineInMinifiedOutput: true,
);
LenientPrintingContext printingContext = LenientPrintingContext();
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index d39958f..b1e5cdb1 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -1860,13 +1860,13 @@
// runtime.
final i = internalizedStringsForJSRuntime.length;
internalizedString = module.globals.import('s', '$i',
- w.GlobalType(w.RefType.extern(nullable: true), mutable: false));
+ w.GlobalType(w.RefType.extern(nullable: false), mutable: false));
internalizedStringsForJSRuntime.add(s);
} else {
internalizedString = module.globals.import(
'S',
s,
- w.GlobalType(w.RefType.extern(nullable: true), mutable: false),
+ w.GlobalType(w.RefType.extern(nullable: false), mutable: false),
);
}
_internalizedStringGlobals[(module, s)] = internalizedString;
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.wat b/pkg/dart2wasm/test/ir_tests/deferred.constant.wat
index d9f9f94..2e3a546 100644
--- a/pkg/dart2wasm/test/ir_tests/deferred.constant.wat
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.wat
@@ -25,8 +25,8 @@
(field $fun (ref $#Closure-0-1)))))
(type $type256 <...>)
(type $#DummyStruct <...>)
- (global $S.globalH1Bar< (import "S" "globalH1Bar<") externref)
- (global $S.globalH0Foo (import "S" "globalH0Foo") externref)
+ (global $S.globalH1Bar< (import "S" "globalH1Bar<") (ref extern))
+ (global $S.globalH0Foo (import "S" "globalH0Foo") (ref extern))
(global $global29 (ref $#DummyStruct) <...>)
(global $"C28 _InterfaceType" (ref $_InterfaceType) <...>)
(global $"C334 \"h0\"" (ref $JSStringImpl) <...>)
diff --git a/pkg/dart2wasm/test/ir_tests/hello.wat b/pkg/dart2wasm/test/ir_tests/hello.wat
index e94dde2..6b9c527 100644
--- a/pkg/dart2wasm/test/ir_tests/hello.wat
+++ b/pkg/dart2wasm/test/ir_tests/hello.wat
@@ -4,7 +4,7 @@
(type $JSStringImpl (sub final $#Top (struct
(field $field0 i32)
(field $_ref externref))))
- (global $"S.hello world" (import "S" "hello world") externref)
+ (global $"S.hello world" (import "S" "hello world") (ref extern))
(global $"C329 \"hello world\"" (ref $JSStringImpl)
(i32.const 4)
(global.get $"S.hello world")
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 35314e4..61e7834 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -11,14 +11,16 @@
final bool utf8;
final bool shouldCompressOutput;
final bool minifyLocalVariables;
+ final bool minifyStatementLabels;
final bool preferSemicolonToNewlineInMinifiedOutput;
const JavaScriptPrintingOptions({
this.utf8 = false,
- this.shouldCompressOutput = false,
- this.minifyLocalVariables = false,
+ bool minify = false,
this.preferSemicolonToNewlineInMinifiedOutput = false,
- });
+ }) : shouldCompressOutput = minify,
+ minifyLocalVariables = minify,
+ minifyStatementLabels = minify;
}
/// An environment in which JavaScript printing is done. Provides emitting of
@@ -89,6 +91,7 @@
final bool shouldCompressOutput;
final DanglingElseVisitor danglingElseVisitor;
final LocalNamer localNamer;
+ final _LabelNamer _labelNamer;
final bool isDebugContext;
int _charCount = 0;
@@ -140,10 +143,10 @@
: isDebugContext = context.isDebugContext,
shouldCompressOutput = options.shouldCompressOutput,
danglingElseVisitor = DanglingElseVisitor(context),
- localNamer = determineRenamer(
- options.shouldCompressOutput,
- options.minifyLocalVariables,
- );
+ localNamer = options.minifyLocalVariables
+ ? MinifyRenamer()
+ : IdentityNamer(),
+ _labelNamer = _LabelNamer(options.minifyStatementLabels);
static LocalNamer determineRenamer(
bool shouldCompressOutput,
@@ -577,7 +580,7 @@
if (node.targetLabel == null) {
outIndent('continue');
} else {
- outIndent('continue ${node.targetLabel}');
+ outIndent('continue ${_labelNamer.mapLabelName(node.targetLabel!)}');
}
outSemicolonLn();
}
@@ -587,7 +590,7 @@
if (node.targetLabel == null) {
outIndent('break');
} else {
- outIndent('break ${node.targetLabel}');
+ outIndent('break ${_labelNamer.mapLabelName(node.targetLabel!)}');
}
outSemicolonLn();
}
@@ -724,7 +727,7 @@
@override
void visitLabeledStatement(LabeledStatement node) {
- outIndent('${node.label}:');
+ outIndent('${_labelNamer.mapLabelName(node.label)}:');
blockBody(node.body, needsSeparation: false, needsNewline: true);
}
@@ -740,7 +743,7 @@
newAtStatementBegin: false,
);
}
- localNamer.enterScope(vars);
+ _enterFunctionScope(vars);
out('(');
visitCommaSeparated(
fun.params,
@@ -771,10 +774,20 @@
shouldIndent: false,
needsNewline: false,
);
- localNamer.leaveScope();
+ _exitFunctionScope();
return closingPosition;
}
+ void _enterFunctionScope(VarCollector vars) {
+ localNamer.enterScope(vars);
+ _labelNamer.enterFunction();
+ }
+
+ void _exitFunctionScope() {
+ _labelNamer.exitFunction();
+ localNamer.leaveScope();
+ }
+
@override
void visitFunctionDeclaration(FunctionDeclaration declaration) {
VarCollector vars = VarCollector();
@@ -1393,7 +1406,7 @@
int arrowFunctionOut(ArrowFunction fun, VarCollector vars) {
// TODO: support static, get/set, async, and generators.
- localNamer.enterScope(vars);
+ _enterFunctionScope(vars);
final List<Parameter> params = fun.params;
if (params.length == 1 && _isIdentifierParameter(params.first)) {
visitNestedExpression(
@@ -1438,7 +1451,7 @@
if (needsParens) out(')');
closingPosition = _charCount;
}
- localNamer.leaveScope();
+ _exitFunctionScope();
return closingPosition;
}
@@ -1637,7 +1650,7 @@
int methodOut(MethodDefinition node, VarCollector vars) {
// TODO: support static, get/set, async, and generators.
Fun fun = node.function;
- localNamer.enterScope(vars);
+ _enterFunctionScope(vars);
out('(');
visitCommaSeparated(
fun.params,
@@ -1652,7 +1665,7 @@
shouldIndent: false,
needsNewline: false,
);
- localNamer.leaveScope();
+ _exitFunctionScope();
return closingPosition;
}
@@ -2139,6 +2152,42 @@
}
}
+class _LabelNamer {
+ final bool renameLabels;
+
+ Map<String, String> _renamings = {};
+
+ final List<Map<String, String>> _outerScopes = [];
+
+ _LabelNamer(this.renameLabels);
+
+ String mapLabelName(String name) {
+ if (!renameLabels) return name;
+ return _renamings[name] ??= _newLabelName(_renamings, name);
+ }
+
+ static String _newLabelName(Map<String, String> renamings, String name) {
+ assert(!renamings.containsKey(name));
+ int index = renamings.length;
+ if (index < 26) return String.fromCharCode(index + 'A'.codeUnitAt(0));
+ index -= 26;
+ if (index < 26) return String.fromCharCode(index + 'a'.codeUnitAt(0));
+ index -= 26;
+ return 'L$index';
+ }
+
+ void enterFunction() {
+ if (!renameLabels) return;
+ _outerScopes.add(_renamings);
+ _renamings = {};
+ }
+
+ void exitFunction() {
+ if (!renameLabels) return;
+ _renamings = _outerScopes.removeLast();
+ }
+}
+
/// Information pertaining the enter and exit callbacks for [node].
class EnterExitNode {
final EnterExitNode? parent;
diff --git a/pkg/js_ast/test/print_helper.dart b/pkg/js_ast/test/print_helper.dart
index 2a9603c..43913ec 100644
--- a/pkg/js_ast/test/print_helper.dart
+++ b/pkg/js_ast/test/print_helper.dart
@@ -56,11 +56,7 @@
}
String prettyPrint(Node node) {
- JavaScriptPrintingOptions options = JavaScriptPrintingOptions(
- shouldCompressOutput: false,
- minifyLocalVariables: false,
- preferSemicolonToNewlineInMinifiedOutput: false,
- );
+ JavaScriptPrintingOptions options = JavaScriptPrintingOptions();
SimpleJavaScriptPrintingContext context = SimpleJavaScriptPrintingContext();
Printer printer = Printer(options, context);
printer.visit(node);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 8c83740..de76ea4 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -47,7 +47,6 @@
ParsedFunction::ParsedFunction(Thread* thread, const Function& function)
: thread_(thread),
function_(function),
- code_(Code::Handle(zone(), function.unoptimized_code())),
scope_(nullptr),
regexp_compile_data_(nullptr),
function_type_arguments_(nullptr),
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 5237e32..070f9c7 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -71,7 +71,6 @@
ParsedFunction(Thread* thread, const Function& function);
const Function& function() const { return function_; }
- const Code& code() const { return code_; }
LocalScope* scope() const { return scope_; }
void set_scope(LocalScope* scope) {
@@ -294,7 +293,6 @@
private:
Thread* thread_;
const Function& function_;
- Code& code_;
LocalScope* scope_;
RegExpCompileData* regexp_compile_data_;
LocalVariable* function_type_arguments_;
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 1c1d472..10ba261 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -396,6 +396,30 @@
throw UnsupportedError("NativeCallable cannot be constructed dynamically.");
}
+ /// Constructs a [NativeCallable] that can be invoked from any thread.
+ ///
+ /// When the native code invokes the function [nativeFunction],
+ /// the [callback] will be executed within the isolate group
+ /// of the [Isolate] which originally constructed the callable.
+ /// Specifically, this means that an attempt to access any
+ /// static or global field which is not shared between
+ /// isolates in a group will result in a [Error].
+ ///
+ /// If an exception is thrown by the [callback], the
+ /// native function will return the `exceptionalReturn`,
+ /// which must be assignable to the return type of
+ /// the [callback].
+ ///
+ /// [callback] and [exceptionalReturn] must be
+ /// _trivially shareable_.
+ ///
+ /// This callback must be [close]d when it is no longer
+ /// needed. An [Isolate] that created the callback will
+ /// be kept alive until [close] is called.
+ ///
+ /// After [NativeCallable.close] is called, invoking
+ /// the [nativeFunction] from native code will cause
+ /// undefined behavior.
factory NativeCallable.isolateGroupBound(
@DartRepresentationOf("T") Function callback, {
Object? exceptionalReturn,
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 12fd963..6b4c9f3 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -12,9 +12,6 @@
function_structs_by_value_generated_ret_test: Pass, Slow # https://dartbug.com/47303 https://dartbug.com/45007
native_assets/asset_*: Pass, Slow # https://dartbug.com/56330
-[ $arch == simarm64_arm64 ]
-many_listener_callbacks_test/*: Pass, Slow
-
[ $builder_tag == optimization_counter_threshold ]
aliasing_test: SkipByDesign # Already has VMOptions=--optimization-counter-threshold
function_callbacks_structs_by_value_generated_test: SkipByDesign # Already has VMOptions=--optimization-counter-threshold
@@ -89,6 +86,9 @@
[ $compiler != dart2analyzer && $compiler != fasta && $runtime != dart_precompiled && $runtime != vm ]
*: SkipByDesign # FFI is a VM-only feature. (This test suite is part of the default set.)
+[ $arch == simarm64_arm64 || $sanitizer == asan || $sanitizer == msan || $sanitizer == tsan ]
+many_listener_callbacks_test/*: Pass, ExtraSlow
+
# These tests trigger and catch an abort (intentionally) and terminate the VM.
# They're incompatible with ASAN because not all memory is freed when aborting and
# with AppJit because the abort the VM before it can generate a snapshot.
diff --git a/tools/VERSION b/tools/VERSION
index f78dfb5..2621cf7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 3
MINOR 11
PATCH 0
-PRERELEASE 69
+PRERELEASE 70
PRERELEASE_PATCH 0