Skip to content

Commit 5cb9ca9

Browse files
[CP-beta]Fix late variable non-assignment when WASM is enabled (flutter#167987)
This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? flutter#167887 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples N/A ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) Tool crashes while running WASM web apps ### Workaround: Is there a workaround for this issue? No ### Risk: What is the risk level of this cherry-pick? ### Test Coverage: Are you confident that your fix is well-tested by automated tests? ### Validation Steps: What are the steps to validate that this fix works? See attached issue
1 parent 3d03881 commit 5cb9ca9

File tree

2 files changed

+123
-31
lines changed

2 files changed

+123
-31
lines changed

packages/flutter_tools/lib/src/isolated/resident_web_runner.dart

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,8 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
435435
final String targetPlatform = getNameForTargetPlatform(TargetPlatform.web_javascript);
436436
final String sdkName = await device!.device!.sdkNameAndVersion;
437437

438-
late UpdateFSReport report;
438+
// Will be null if there is no report.
439+
final UpdateFSReport? report;
439440
if (debuggingOptions.buildInfo.isDebug && !debuggingOptions.webUseWasm) {
440441
await runSourceGenerators();
441442
// Don't reset the resident compiler for web, since the extra recompile is
@@ -469,6 +470,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
469470
return OperationResult(1, 'Failed to recompile application.');
470471
}
471472
} else {
473+
report = null;
472474
try {
473475
final WebBuilder webBuilder = WebBuilder(
474476
logger: _logger,
@@ -490,8 +492,9 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
490492
}
491493
}
492494

493-
late Duration reloadDuration;
494-
late Duration reassembleDuration;
495+
// Both will be null when not assigned.
496+
Duration? reloadDuration;
497+
Duration? reassembleDuration;
495498
try {
496499
if (!deviceIsDebuggable) {
497500
_logger.printStatus('Recompile complete. Page requires refresh.');
@@ -578,12 +581,12 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
578581
fullRestart: true,
579582
reason: reason,
580583
overallTimeInMs: elapsed.inMilliseconds,
581-
syncedBytes: report.syncedBytes,
582-
invalidatedSourcesCount: report.invalidatedSourcesCount,
583-
transferTimeInMs: report.transferDuration.inMilliseconds,
584-
compileTimeInMs: report.compileDuration.inMilliseconds,
585-
findInvalidatedTimeInMs: report.findInvalidatedDuration.inMilliseconds,
586-
scannedSourcesCount: report.scannedSourcesCount,
584+
syncedBytes: report?.syncedBytes,
585+
invalidatedSourcesCount: report?.invalidatedSourcesCount,
586+
transferTimeInMs: report?.transferDuration.inMilliseconds,
587+
compileTimeInMs: report?.compileDuration.inMilliseconds,
588+
findInvalidatedTimeInMs: report?.findInvalidatedDuration.inMilliseconds,
589+
scannedSourcesCount: report?.scannedSourcesCount,
587590
).send();
588591
_analytics.send(
589592
Event.hotRunnerInfo(
@@ -594,12 +597,12 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
594597
fullRestart: true,
595598
reason: reason,
596599
overallTimeInMs: elapsed.inMilliseconds,
597-
syncedBytes: report.syncedBytes,
598-
invalidatedSourcesCount: report.invalidatedSourcesCount,
599-
transferTimeInMs: report.transferDuration.inMilliseconds,
600-
compileTimeInMs: report.compileDuration.inMilliseconds,
601-
findInvalidatedTimeInMs: report.findInvalidatedDuration.inMilliseconds,
602-
scannedSourcesCount: report.scannedSourcesCount,
600+
syncedBytes: report?.syncedBytes,
601+
invalidatedSourcesCount: report?.invalidatedSourcesCount,
602+
transferTimeInMs: report?.transferDuration.inMilliseconds,
603+
compileTimeInMs: report?.compileDuration.inMilliseconds,
604+
findInvalidatedTimeInMs: report?.findInvalidatedDuration.inMilliseconds,
605+
scannedSourcesCount: report?.scannedSourcesCount,
603606
),
604607
);
605608
} else {
@@ -618,14 +621,14 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
618621
fullRestart: false,
619622
reason: reason,
620623
overallTimeInMs: elapsed.inMilliseconds,
621-
syncedBytes: report.syncedBytes,
622-
invalidatedSourcesCount: report.invalidatedSourcesCount,
623-
transferTimeInMs: report.transferDuration.inMilliseconds,
624-
compileTimeInMs: report.compileDuration.inMilliseconds,
625-
findInvalidatedTimeInMs: report.findInvalidatedDuration.inMilliseconds,
626-
scannedSourcesCount: report.scannedSourcesCount,
627-
reassembleTimeInMs: reassembleDuration.inMilliseconds,
628-
reloadVMTimeInMs: reloadDuration.inMilliseconds,
624+
syncedBytes: report?.syncedBytes,
625+
invalidatedSourcesCount: report?.invalidatedSourcesCount,
626+
transferTimeInMs: report?.transferDuration.inMilliseconds,
627+
compileTimeInMs: report?.compileDuration.inMilliseconds,
628+
findInvalidatedTimeInMs: report?.findInvalidatedDuration.inMilliseconds,
629+
scannedSourcesCount: report?.scannedSourcesCount,
630+
reassembleTimeInMs: reassembleDuration?.inMilliseconds,
631+
reloadVMTimeInMs: reloadDuration?.inMilliseconds,
629632
).send();
630633
_analytics.send(
631634
Event.hotRunnerInfo(
@@ -636,14 +639,14 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
636639
fullRestart: false,
637640
reason: reason,
638641
overallTimeInMs: elapsed.inMilliseconds,
639-
syncedBytes: report.syncedBytes,
640-
invalidatedSourcesCount: report.invalidatedSourcesCount,
641-
transferTimeInMs: report.transferDuration.inMilliseconds,
642-
compileTimeInMs: report.compileDuration.inMilliseconds,
643-
findInvalidatedTimeInMs: report.findInvalidatedDuration.inMilliseconds,
644-
scannedSourcesCount: report.scannedSourcesCount,
645-
reassembleTimeInMs: reassembleDuration.inMilliseconds,
646-
reloadVMTimeInMs: reloadDuration.inMilliseconds,
642+
syncedBytes: report?.syncedBytes,
643+
invalidatedSourcesCount: report?.invalidatedSourcesCount,
644+
transferTimeInMs: report?.transferDuration.inMilliseconds,
645+
compileTimeInMs: report?.compileDuration.inMilliseconds,
646+
findInvalidatedTimeInMs: report?.findInvalidatedDuration.inMilliseconds,
647+
scannedSourcesCount: report?.scannedSourcesCount,
648+
reassembleTimeInMs: reassembleDuration?.inMilliseconds,
649+
reloadVMTimeInMs: reloadDuration?.inMilliseconds,
647650
),
648651
);
649652
}

packages/flutter_tools/test/general.shard/resident_web_runner_test.dart

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import 'package:flutter_tools/src/base/platform.dart';
1717
import 'package:flutter_tools/src/base/terminal.dart';
1818
import 'package:flutter_tools/src/base/time.dart';
1919
import 'package:flutter_tools/src/build_info.dart';
20+
import 'package:flutter_tools/src/build_system/build_system.dart';
2021
import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart';
2122
import 'package:flutter_tools/src/compile.dart';
2223
import 'package:flutter_tools/src/dart/pub.dart';
@@ -46,6 +47,7 @@ import '../src/fake_pub_deps.dart';
4647
import '../src/fake_vm_services.dart';
4748
import '../src/fakes.dart' as test_fakes;
4849
import '../src/package_config.dart';
50+
import '../src/test_build_system.dart';
4951

5052
const List<VmServiceExpectation> kAttachLogExpectations = <VmServiceExpectation>[
5153
FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{'streamId': 'Stdout'}),
@@ -914,6 +916,88 @@ name: my_app
914916
},
915917
);
916918

919+
// Regression test for https://github.com/flutter/flutter/issues/167887.
920+
testUsingContext(
921+
'WASM builds report analysis without crashing',
922+
() async {
923+
final BufferLogger logger = BufferLogger.test();
924+
final ResidentRunner residentWebRunner = setUpResidentRunner(
925+
flutterDevice,
926+
logger: logger,
927+
systemClock: SystemClock.fixed(DateTime(2001)),
928+
debuggingOptions: DebuggingOptions.enabled(
929+
const BuildInfo(
930+
BuildMode.debug,
931+
null,
932+
trackWidgetCreation: true,
933+
treeShakeIcons: false,
934+
packageConfigPath: '.dart_tool/package_config.json',
935+
// Hot reload only supported with these flags for now.
936+
extraFrontEndOptions: kDdcLibraryBundleFlags,
937+
),
938+
webUseWasm: true,
939+
),
940+
);
941+
fakeVmServiceHost = FakeVmServiceHost(
942+
requests: <VmServiceExpectation>[
943+
...kAttachExpectations,
944+
const FakeVmServiceRequest(
945+
method: kReloadSourcesServiceName,
946+
args: <String, Object>{'isolateId': ''},
947+
jsonResponse: <String, Object>{'type': 'ReloadReport', 'success': true},
948+
),
949+
const FakeVmServiceRequest(
950+
method: 'ext.flutter.reassemble',
951+
jsonResponse: <String, Object>{'type': 'ReloadReport', 'success': true},
952+
),
953+
const FakeVmServiceRequest(
954+
method: 'streamListen',
955+
args: <String, Object>{'streamId': 'Isolate'},
956+
),
957+
],
958+
);
959+
setupMocks();
960+
final TestChromiumLauncher chromiumLauncher = TestChromiumLauncher();
961+
final FakeProcess process = FakeProcess();
962+
final Chromium chrome = Chromium(
963+
1,
964+
chromeConnection,
965+
chromiumLauncher: chromiumLauncher,
966+
process: process,
967+
logger: logger,
968+
);
969+
chromiumLauncher.setInstance(chrome);
970+
971+
flutterDevice.device = GoogleChromeDevice(
972+
fileSystem: fileSystem,
973+
chromiumLauncher: chromiumLauncher,
974+
logger: BufferLogger.test(),
975+
platform: FakePlatform(),
976+
processManager: FakeProcessManager.any(),
977+
);
978+
webDevFS.report = UpdateFSReport(success: true);
979+
980+
final Completer<DebugConnectionInfo> connectionInfoCompleter =
981+
Completer<DebugConnectionInfo>();
982+
unawaited(residentWebRunner.run(connectionInfoCompleter: connectionInfoCompleter));
983+
final DebugConnectionInfo debugConnectionInfo = await connectionInfoCompleter.future;
984+
985+
expect(debugConnectionInfo, isNotNull);
986+
987+
final OperationResult result = await residentWebRunner.restart();
988+
expect(logger.statusText, contains('Reloaded application in'));
989+
expect(result.code, 0);
990+
},
991+
overrides: <Type, Generator>{
992+
Analytics: () => fakeAnalytics,
993+
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
994+
FileSystem: () => fileSystem,
995+
ProcessManager: () => processManager,
996+
FeatureFlags: enableExplicitPackageDependencies,
997+
Pub: FakePubWithPrimedDeps.new,
998+
},
999+
);
1000+
9171001
// Hot restart is available with and without the DDC library bundle format.
9181002
// Test one extra config where `fullRestart` is false without the DDC library
9191003
// bundle format - we should do a hot restart in this case because hot reload
@@ -1995,6 +2079,11 @@ class FakeChromeTab extends Fake implements ChromeTab {
19952079
class FakeWipConnection extends Fake implements WipConnection {
19962080
@override
19972081
final WipDebugger debugger = FakeWipDebugger();
2082+
2083+
@override
2084+
Future<WipResponse> sendCommand(String method, [Map<String, dynamic>? params]) async {
2085+
return WipResponse(<String, dynamic>{'id': 0, 'result': <String, dynamic>{}});
2086+
}
19982087
}
19992088

20002089
/// A test implementation of the [ChromiumLauncher] that launches a fixed instance.

0 commit comments

Comments
 (0)