Track async microtasks scheduled by macros, and ensure they have all completed before a macro returns.
Does not track certain events such as async I/O, but will refuse to execute the scheduled callbacks when those do complete.
Bug: https://github.com/dart-lang/sdk/issues/55426
Change-Id: Ie81100e9e4dbe49d050bad875cc9b6a65969863d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370120
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Morgan :) <davidmorgan@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_macros/CHANGELOG.md b/pkg/_macros/CHANGELOG.md
index 5fa4a7d..ac85572 100644
--- a/pkg/_macros/CHANGELOG.md
+++ b/pkg/_macros/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.1
+
+- Make it an error for macros to complete with pending async work scheduled.
+
## 0.3.0
- Remove type parameter on internal `StaticType` implementation.
diff --git a/pkg/_macros/lib/src/executor/client.dart b/pkg/_macros/lib/src/executor/client.dart
index 5be2a4c..8dfc7814 100644
--- a/pkg/_macros/lib/src/executor/client.dart
+++ b/pkg/_macros/lib/src/executor/client.dart
@@ -215,8 +215,8 @@
remoteInstance: request.introspector,
serializationZoneId: request.serializationZoneId);
- MacroExecutionResult result =
- await executeTypesMacro(instance, request.target, introspector);
+ MacroExecutionResult result = await runPhase(
+ () => executeTypesMacro(instance, request.target, introspector));
return SerializableResponse(
responseType: MessageType.macroExecutionResult,
response: result,
@@ -244,8 +244,8 @@
remoteInstance: request.introspector,
serializationZoneId: request.serializationZoneId);
- MacroExecutionResult result = await executeDeclarationsMacro(
- instance, request.target, introspector);
+ MacroExecutionResult result = await runPhase(() =>
+ executeDeclarationsMacro(instance, request.target, introspector));
return SerializableResponse(
responseType: MessageType.macroExecutionResult,
response: result,
@@ -272,8 +272,8 @@
remoteInstance: request.introspector,
serializationZoneId: request.serializationZoneId);
- MacroExecutionResult result =
- await executeDefinitionMacro(instance, request.target, introspector);
+ MacroExecutionResult result = await runPhase(
+ () => executeDefinitionMacro(instance, request.target, introspector));
return SerializableResponse(
responseType: MessageType.macroExecutionResult,
response: result,
@@ -339,3 +339,85 @@
'ProcessExecutor');
}
};
+
+/// Runs [phase] in a [Zone] which tracks scheduled tasks, completing with a
+/// [StateError] if [phase] returns a value while additional tasks or timers
+/// are still scheduled.
+Future<MacroExecutionResult> runPhase(
+ Future<MacroExecutionResult> Function() phase) {
+ final completer = Completer<MacroExecutionResult>();
+
+ var pendingMicrotasks = 0;
+ var activeTimers = 0;
+ Zone.current
+ .fork(
+ specification: ZoneSpecification(
+ handleUncaughtError: (self, parent, zone, error, stackTrace) {
+ if (completer.isCompleted) return;
+ completer.completeError(error, stackTrace);
+ },
+ createTimer: (self, parent, zone, duration, f) {
+ activeTimers++;
+ return _WrappedTimer(
+ parent.createTimer(zone, duration, () {
+ activeTimers--;
+ f();
+ }),
+ onCancel: () => activeTimers--);
+ },
+ createPeriodicTimer: (self, parent, zone, duration, f) {
+ activeTimers++;
+ return _WrappedTimer(parent.createPeriodicTimer(zone, duration, f),
+ onCancel: () => activeTimers--);
+ },
+ scheduleMicrotask: (self, parent, zone, f) {
+ pendingMicrotasks++;
+ parent.scheduleMicrotask(zone, () {
+ pendingMicrotasks--;
+ assert(pendingMicrotasks >= 0);
+ // This should only happen if we have previously competed with an
+ // error. Just skip this scheduled task in that case.
+ if (completer.isCompleted) return;
+ f();
+ });
+ },
+ ))
+ .runGuarded(() => phase().then((value) {
+ if (completer.isCompleted) return;
+ if (pendingMicrotasks != 0) {
+ throw StateError(
+ 'Macro completed but has $pendingMicrotasks async tasks still '
+ 'pending. Macros must complete all async work prior to '
+ 'returning.');
+ }
+ if (activeTimers != 0) {
+ throw StateError(
+ 'Macro completed but has $activeTimers active timers. '
+ 'Macros must cancel all timers prior to returning.');
+ }
+ completer.complete(value);
+ }));
+ return completer.future;
+}
+
+/// Wraps a [Timer] to track when it is cancelled and calls [onCancel], if the
+/// timer is still active.
+class _WrappedTimer implements Timer {
+ final Timer timer;
+
+ final void Function() onCancel;
+
+ _WrappedTimer(this.timer, {required this.onCancel});
+
+ @override
+ void cancel() {
+ if (isActive) onCancel();
+ timer.cancel();
+ }
+
+ @override
+ bool get isActive => timer.isActive;
+
+ @override
+ int get tick => timer.tick;
+}
diff --git a/pkg/_macros/pubspec.yaml b/pkg/_macros/pubspec.yaml
index d2ee9ab..a63458b 100644
--- a/pkg/_macros/pubspec.yaml
+++ b/pkg/_macros/pubspec.yaml
@@ -1,5 +1,5 @@
name: _macros
-version: 0.3.0
+version: 0.3.1
description: >-
This is a private SDK vendored package, which is re-exported by the public
`macros` package, which is a pub package. Every change to this package is
diff --git a/pkg/_macros/test/executor/executor_test.dart b/pkg/_macros/test/executor/executor_test.dart
index 929eed2..89f32ce 100644
--- a/pkg/_macros/test/executor/executor_test.dart
+++ b/pkg/_macros/test/executor/executor_test.dart
@@ -21,8 +21,14 @@
void main() {
late MacroExecutor executor;
late File kernelOutputFile;
+ final danglingTaskMacroName = 'DanglingTaskMacro';
+ final danglingTimerMacroName = 'DanglingTimerMacro';
+ final danglingPeriodicTimerMacroName = 'DanglingPeriodicTimerMacro';
final diagnosticMacroName = 'DiagnosticMacro';
final simpleMacroName = 'SimpleMacro';
+ late MacroInstanceIdentifier danglingTaskMacroId;
+ late MacroInstanceIdentifier danglingTimerMacroId;
+ late MacroInstanceIdentifier danglingPeriodicTimerMacroId;
late MacroInstanceIdentifier diagnosticMacroInstanceId;
late MacroInstanceIdentifier simpleMacroInstanceId;
late Uri macroUri;
@@ -46,6 +52,9 @@
var bootstrapContent = bootstrapMacroIsolate({
macroUri.toString(): {
simpleMacroName: ['', 'named'],
+ danglingTaskMacroName: [''],
+ danglingTimerMacroName: [''],
+ danglingPeriodicTimerMacroName: [''],
diagnosticMacroName: [''],
}
}, mode);
@@ -129,6 +138,21 @@
expect(simpleMacroInstanceId, isNotNull,
reason: 'Can create an instance with named arguments.');
+ danglingTaskMacroId = await executor.instantiateMacro(
+ macroUri, danglingTaskMacroName, '', Arguments([], {}));
+ expect(danglingTaskMacroId, isNotNull);
+
+ danglingTimerMacroId = await executor.instantiateMacro(
+ macroUri, danglingTimerMacroName, '', Arguments([], {}));
+ expect(danglingTimerMacroId, isNotNull);
+
+ danglingPeriodicTimerMacroId = await executor.instantiateMacro(
+ macroUri,
+ danglingPeriodicTimerMacroName,
+ '',
+ Arguments([], {}));
+ expect(danglingPeriodicTimerMacroId, isNotNull);
+
diagnosticMacroInstanceId = await executor.instantiateMacro(
macroUri, diagnosticMacroName, '', Arguments([], {}));
expect(diagnosticMacroInstanceId, isNotNull);
@@ -401,6 +425,36 @@
'''),
);
});
+
+ test('Cannot leave dangling tasks', () async {
+ expect(
+ () => executor.executeTypesPhase(danglingTaskMacroId,
+ Fixtures.library, TestTypePhaseIntrospector()),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 async tasks still pending')),
+ ));
+ });
+
+ test('Cannot leave dangling timers', () async {
+ expect(
+ () => executor.executeTypesPhase(danglingTimerMacroId,
+ Fixtures.library, TestTypePhaseIntrospector()),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 active timers')),
+ ));
+
+ expect(
+ () => executor.executeTypesPhase(
+ danglingPeriodicTimerMacroId,
+ Fixtures.library,
+ TestTypePhaseIntrospector()),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 active timers')),
+ ));
+ });
});
group('in the declaration phase', () {
@@ -666,6 +720,40 @@
equalsIgnoringWhitespace('final LibraryInfo library;'),
);
});
+
+ test('Cannot leave dangling tasks', () async {
+ expect(
+ () => executor.executeDeclarationsPhase(
+ danglingTaskMacroId,
+ Fixtures.library,
+ Fixtures.testDeclarationPhaseIntrospector),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 async tasks still pending')),
+ ));
+ });
+
+ test('Cannot leave dangling timers', () async {
+ expect(
+ () => executor.executeDeclarationsPhase(
+ danglingTimerMacroId,
+ Fixtures.library,
+ Fixtures.testDeclarationPhaseIntrospector),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 active timers')),
+ ));
+
+ expect(
+ () => executor.executeDeclarationsPhase(
+ danglingPeriodicTimerMacroId,
+ Fixtures.library,
+ Fixtures.testDeclarationPhaseIntrospector),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 active timers')),
+ ));
+ });
});
group('in the definition phase', () {
@@ -961,6 +1049,40 @@
augment final LibraryInfo library = LibraryInfo(Uri.parse('package:foo/bar.dart'), '3.0', [MyClass, MyEnum, MyMixin, ]);
'''));
});
+
+ test('Cannot leave dangling tasks', () async {
+ expect(
+ () => executor.executeDefinitionsPhase(
+ danglingTaskMacroId,
+ Fixtures.library,
+ Fixtures.testDefinitionPhaseIntrospector),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 async tasks still pending')),
+ ));
+ });
+
+ test('Cannot leave dangling timers', () async {
+ expect(
+ () => executor.executeDefinitionsPhase(
+ danglingTimerMacroId,
+ Fixtures.library,
+ Fixtures.testDefinitionPhaseIntrospector),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 active timers')),
+ ));
+
+ expect(
+ () => executor.executeDefinitionsPhase(
+ danglingPeriodicTimerMacroId,
+ Fixtures.library,
+ Fixtures.testDefinitionPhaseIntrospector),
+ throwsA(
+ isA<UnexpectedMacroException>().having((e) => e.message,
+ 'message', contains('1 active timers')),
+ ));
+ });
});
test('and report diagnostics', () async {
diff --git a/pkg/_macros/test/executor/simple_macro.dart b/pkg/_macros/test/executor/simple_macro.dart
index 4f110fe..c595707 100644
--- a/pkg/_macros/test/executor/simple_macro.dart
+++ b/pkg/_macros/test/executor/simple_macro.dart
@@ -802,6 +802,75 @@
]);
}
+class DanglingTaskMacro
+ implements
+ LibraryTypesMacro,
+ LibraryDeclarationsMacro,
+ LibraryDefinitionMacro {
+ @override
+ void buildTypesForLibrary(Library library, TypeBuilder builder) {
+ Future.value('hello').then((_) => Future.value('world'));
+ }
+
+ @override
+ void buildDeclarationsForLibrary(
+ Library library, DeclarationBuilder builder) {
+ Future.value('hello').then((_) => Future.value('world'));
+ }
+
+ @override
+ FutureOr<void> buildDefinitionForLibrary(
+ Library library, LibraryDefinitionBuilder builder) {
+ Future.value('hello').then((_) => Future.value('world'));
+ }
+}
+
+class DanglingTimerMacro
+ implements
+ LibraryTypesMacro,
+ LibraryDeclarationsMacro,
+ LibraryDefinitionMacro {
+ @override
+ void buildTypesForLibrary(Library library, TypeBuilder builder) {
+ Timer.run(() {});
+ }
+
+ @override
+ void buildDeclarationsForLibrary(
+ Library library, DeclarationBuilder builder) {
+ Timer.run(() {});
+ }
+
+ @override
+ FutureOr<void> buildDefinitionForLibrary(
+ Library library, LibraryDefinitionBuilder builder) {
+ Timer.run(() {});
+ }
+}
+
+class DanglingPeriodicTimerMacro
+ implements
+ LibraryTypesMacro,
+ LibraryDeclarationsMacro,
+ LibraryDefinitionMacro {
+ @override
+ void buildTypesForLibrary(Library library, TypeBuilder builder) {
+ Timer.periodic(Duration(seconds: 1), (_) {});
+ }
+
+ @override
+ void buildDeclarationsForLibrary(
+ Library library, DeclarationBuilder builder) {
+ Timer.periodic(Duration(seconds: 1), (_) {});
+ }
+
+ @override
+ FutureOr<void> buildDefinitionForLibrary(
+ Library library, LibraryDefinitionBuilder builder) {
+ Timer.periodic(Duration(seconds: 1), (_) {});
+ }
+}
+
extension on String {
String capitalize() => '${this[0].toUpperCase()}${substring(1)}';
}
diff --git a/pkg/front_end/test/macros/application/data/tests/crash.dart.expect b/pkg/front_end/test/macros/application/data/tests/crash.dart.expect
index 5373a5b..a18d56f 100644
--- a/pkg/front_end/test/macros/application/data/tests/crash.dart.expect
+++ b/pkg/front_end/test/macros/application/data/tests/crash.dart.expect
@@ -8,22 +8,28 @@
// org-dartlang-test:///a/b/c/main.dart:7:2: Context: Error in buildTypesForClass
// #0 CrashTypesMacro.buildTypesForClass (package:macro/crash.dart:13:5)
// #1 executeTypesMacro (package:_macros/src/executor/execute_macro.dart:39:21)
-// #2 MacroExpansionClient._executeTypesPhase (package:_macros/src/executor/client.dart:219:17)
-// #3 MacroExpansionClient._handleMessage.<anonymous closure> (package:_macros/src/executor/client.dart:145:18)
+// #2 MacroExpansionClient._executeTypesPhase.<anonymous closure> (package:_macros/src/executor/client.dart:219:17)
+// #3 runPhase.<anonymous closure> (package:_macros/src/executor/client.dart:385:30)
// #4 _rootRun (dart:async/zone.dart:1399:13)
// #5 _CustomZone.run (dart:async/zone.dart:1301:19)
-// #6 withRemoteInstanceZone (package:_macros/src/executor/remote_instance.dart:172:15)
-// #7 MacroExpansionClient._handleMessage (package:_macros/src/executor/client.dart:118:11)
-// #8 new MacroExpansionClient._.<anonymous closure> (package:_macros/src/executor/client.dart:37:39)
-// #9 _rootRunUnary (dart:async/zone.dart:1415:13)
-// #10 _CustomZone.runUnary (dart:async/zone.dart:1308:19)
-// #11 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
-// #12 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
-// #13 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
-// #14 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
-// #15 _StreamController._add (dart:async/stream_controller.dart:658:7)
-// #16 _StreamController.add (dart:async/stream_controller.dart:606:5)
-// #17 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
+// #6 _CustomZone.runGuarded (dart:async/zone.dart:1209:7)
+// #7 runPhase (package:_macros/src/executor/client.dart:385:8)
+// #8 MacroExpansionClient._executeTypesPhase (package:_macros/src/executor/client.dart:218:43)
+// #9 MacroExpansionClient._handleMessage.<anonymous closure> (package:_macros/src/executor/client.dart:145:18)
+// #10 _rootRun (dart:async/zone.dart:1399:13)
+// #11 _CustomZone.run (dart:async/zone.dart:1301:19)
+// #12 withRemoteInstanceZone (package:_macros/src/executor/remote_instance.dart:172:15)
+// #13 MacroExpansionClient._handleMessage (package:_macros/src/executor/client.dart:118:11)
+// #14 new MacroExpansionClient._.<anonymous closure> (package:_macros/src/executor/client.dart:37:39)
+// #15 _rootRunUnary (dart:async/zone.dart:1415:13)
+// #16 _CustomZone.runUnary (dart:async/zone.dart:1308:19)
+// #17 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
+// #18 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
+// #19 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
+// #20 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
+// #21 _StreamController._add (dart:async/stream_controller.dart:658:7)
+// #22 _StreamController.add (dart:async/stream_controller.dart:606:5)
+// #23 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
//
// @CrashTypesMacro()
// ^
@@ -34,22 +40,28 @@
// org-dartlang-test:///a/b/c/main.dart:8:2: Context: Error in buildDeclarationsForClass
// #0 CrashDeclarationsMacro.buildDeclarationsForClass (package:macro/crash.dart:22:5)
// #1 executeDeclarationsMacro (package:_macros/src/executor/execute_macro.dart:107:21)
-// #2 MacroExpansionClient._executeDeclarationsPhase (package:_macros/src/executor/client.dart:247:43)
-// #3 MacroExpansionClient._handleMessage.<anonymous closure> (package:_macros/src/executor/client.dart:135:18)
+// #2 MacroExpansionClient._executeDeclarationsPhase.<anonymous closure> (package:_macros/src/executor/client.dart:248:11)
+// #3 runPhase.<anonymous closure> (package:_macros/src/executor/client.dart:385:30)
// #4 _rootRun (dart:async/zone.dart:1399:13)
// #5 _CustomZone.run (dart:async/zone.dart:1301:19)
-// #6 withRemoteInstanceZone (package:_macros/src/executor/remote_instance.dart:172:15)
-// #7 MacroExpansionClient._handleMessage (package:_macros/src/executor/client.dart:118:11)
-// #8 new MacroExpansionClient._.<anonymous closure> (package:_macros/src/executor/client.dart:37:39)
-// #9 _rootRunUnary (dart:async/zone.dart:1415:13)
-// #10 _CustomZone.runUnary (dart:async/zone.dart:1308:19)
-// #11 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
-// #12 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
-// #13 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
-// #14 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
-// #15 _StreamController._add (dart:async/stream_controller.dart:658:7)
-// #16 _StreamController.add (dart:async/stream_controller.dart:606:5)
-// #17 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
+// #6 _CustomZone.runGuarded (dart:async/zone.dart:1209:7)
+// #7 runPhase (package:_macros/src/executor/client.dart:385:8)
+// #8 MacroExpansionClient._executeDeclarationsPhase (package:_macros/src/executor/client.dart:247:43)
+// #9 MacroExpansionClient._handleMessage.<anonymous closure> (package:_macros/src/executor/client.dart:135:18)
+// #10 _rootRun (dart:async/zone.dart:1399:13)
+// #11 _CustomZone.run (dart:async/zone.dart:1301:19)
+// #12 withRemoteInstanceZone (package:_macros/src/executor/remote_instance.dart:172:15)
+// #13 MacroExpansionClient._handleMessage (package:_macros/src/executor/client.dart:118:11)
+// #14 new MacroExpansionClient._.<anonymous closure> (package:_macros/src/executor/client.dart:37:39)
+// #15 _rootRunUnary (dart:async/zone.dart:1415:13)
+// #16 _CustomZone.runUnary (dart:async/zone.dart:1308:19)
+// #17 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
+// #18 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
+// #19 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
+// #20 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
+// #21 _StreamController._add (dart:async/stream_controller.dart:658:7)
+// #22 _StreamController.add (dart:async/stream_controller.dart:606:5)
+// #23 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
//
// @CrashDeclarationsMacro()
// ^
@@ -60,22 +72,28 @@
// org-dartlang-test:///a/b/c/main.dart:9:2: Context: Error in buildDefinitionForClass
// #0 CrashDefinitionMacro.buildDefinitionForClass (package:macro/crash.dart:31:5)
// #1 executeDefinitionMacro (package:_macros/src/executor/execute_macro.dart:167:21)
-// #2 MacroExpansionClient._executeDefinitionsPhase (package:_macros/src/executor/client.dart:276:17)
-// #3 MacroExpansionClient._handleMessage.<anonymous closure> (package:_macros/src/executor/client.dart:140:18)
+// #2 MacroExpansionClient._executeDefinitionsPhase.<anonymous closure> (package:_macros/src/executor/client.dart:276:17)
+// #3 runPhase.<anonymous closure> (package:_macros/src/executor/client.dart:385:30)
// #4 _rootRun (dart:async/zone.dart:1399:13)
// #5 _CustomZone.run (dart:async/zone.dart:1301:19)
-// #6 withRemoteInstanceZone (package:_macros/src/executor/remote_instance.dart:172:15)
-// #7 MacroExpansionClient._handleMessage (package:_macros/src/executor/client.dart:118:11)
-// #8 new MacroExpansionClient._.<anonymous closure> (package:_macros/src/executor/client.dart:37:39)
-// #9 _rootRunUnary (dart:async/zone.dart:1415:13)
-// #10 _CustomZone.runUnary (dart:async/zone.dart:1308:19)
-// #11 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
-// #12 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
-// #13 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
-// #14 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
-// #15 _StreamController._add (dart:async/stream_controller.dart:658:7)
-// #16 _StreamController.add (dart:async/stream_controller.dart:606:5)
-// #17 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
+// #6 _CustomZone.runGuarded (dart:async/zone.dart:1209:7)
+// #7 runPhase (package:_macros/src/executor/client.dart:385:8)
+// #8 MacroExpansionClient._executeDefinitionsPhase (package:_macros/src/executor/client.dart:275:43)
+// #9 MacroExpansionClient._handleMessage.<anonymous closure> (package:_macros/src/executor/client.dart:140:18)
+// #10 _rootRun (dart:async/zone.dart:1399:13)
+// #11 _CustomZone.run (dart:async/zone.dart:1301:19)
+// #12 withRemoteInstanceZone (package:_macros/src/executor/remote_instance.dart:172:15)
+// #13 MacroExpansionClient._handleMessage (package:_macros/src/executor/client.dart:118:11)
+// #14 new MacroExpansionClient._.<anonymous closure> (package:_macros/src/executor/client.dart:37:39)
+// #15 _rootRunUnary (dart:async/zone.dart:1415:13)
+// #16 _CustomZone.runUnary (dart:async/zone.dart:1308:19)
+// #17 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
+// #18 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
+// #19 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
+// #20 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
+// #21 _StreamController._add (dart:async/stream_controller.dart:658:7)
+// #22 _StreamController.add (dart:async/stream_controller.dart:606:5)
+// #23 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
//
// @CrashDefinitionMacro()
// ^
diff --git a/pkg/macros/CHANGELOG.md b/pkg/macros/CHANGELOG.md
index d5562b6..a37161c 100644
--- a/pkg/macros/CHANGELOG.md
+++ b/pkg/macros/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.2-main.1
+
+- Make it an error for macros to complete with pending async work scheduled.
+
## 0.1.2-main.0
- Remove type parameter on internal `StaticType` implementation.
diff --git a/pkg/macros/pubspec.yaml b/pkg/macros/pubspec.yaml
index 6eef826..5271f4f 100644
--- a/pkg/macros/pubspec.yaml
+++ b/pkg/macros/pubspec.yaml
@@ -1,5 +1,5 @@
name: macros
-version: 0.1.2-main.0
+version: 0.1.2-main.1
description: >-
This package is for macro authors, and exposes the APIs necessary to write
a macro. It exports the APIs from the private `_macros` SDK vendored package.
@@ -11,4 +11,4 @@
dependencies:
_macros:
sdk: dart
- version: 0.3.0
+ version: 0.3.1