diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index f1cb02f2c..77e8a1f68 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,3 +1,9 @@ +## 16.0.2+1 + +- Handle the case where `list.objectId` is `null` in + `batched_expression_evaluator` to fix crash on Flutter 3.7.0: + https://github.com/flutter/flutter/issues/119084 + ## 16.0.2 - Don't complete an already completed `Completer` in `ChromeProxyService` to fix Flutter tools crash: https://github.com/dart-lang/webdev/pull/1862 diff --git a/dwds/lib/src/services/batched_expression_evaluator.dart b/dwds/lib/src/services/batched_expression_evaluator.dart index 64338fd38..76ee96880 100644 --- a/dwds/lib/src/services/batched_expression_evaluator.dart +++ b/dwds/lib/src/services/batched_expression_evaluator.dart @@ -121,15 +121,23 @@ class BatchedExpressionEvaluator extends ExpressionEvaluator { final request = requests[i]; if (request.completer.isCompleted) continue; _logger.fine('Getting result out of a batch for ${request.expression}'); - _debugger - .getProperties(list.objectId!, - offset: i, count: 1, length: requests.length) - .then((v) { - final result = v.first.value; - _logger.fine( - 'Got result out of a batch for ${request.expression}: $result'); - request.completer.complete(result); - }); + final listId = list.objectId; + if (listId == null) { + final error = RemoteObject({ + 'type': '${ErrorKind.internal}', + 'value': 'No batch result object ID.' + }); + request.completer.complete(error); + } else { + _debugger + .getProperties(listId, offset: i, count: 1, length: requests.length) + .then((v) { + final result = v.first.value; + _logger.fine( + 'Got result out of a batch for ${request.expression}: $result'); + request.completer.complete(result); + }); + } } } } diff --git a/dwds/test/evaluate_common.dart b/dwds/test/evaluate_common.dart index b03ceff5b..8b8b41086 100644 --- a/dwds/test/evaluate_common.dart +++ b/dwds/test/evaluate_common.dart @@ -558,6 +558,32 @@ void testAll({ (instance) => instance.valueAsString, 'valueAsString', '1')); }); + test('in parallel (in a batch) handles errors', () async { + final library = isolate.rootLib!; + final missingLibId = ''; + final evaluation1 = setup.service + .evaluate(isolateId, missingLibId, 'MainClass(0).toString()'); + final evaluation2 = setup.service + .evaluate(isolateId, library.id!, 'MainClass(1).toString()'); + + final results = await Future.wait([evaluation1, evaluation2]); + + expect( + results[0], + isA().having( + (instance) => instance.message, + 'message', + contains('No batch result object ID'), + )); + expect( + results[1], + isA().having( + (instance) => instance.message, + 'message', + contains('No batch result object ID'), + )); + }); + test('with scope override', () async { final library = isolate.rootLib!; final object = await setup.service