Some fixes for dart2wasm (#38167)

* A few fixes to get things compiling via dart2wasm.

* Use `futureToPromise`.

* Some more fixes for dart2wasm.

* Allow promises to have nullable objects.
diff --git a/lib/web_ui/lib/src/engine/app_bootstrap.dart b/lib/web_ui/lib/src/engine/app_bootstrap.dart
index 6d76f0c..f930b87 100644
--- a/lib/web_ui/lib/src/engine/app_bootstrap.dart
+++ b/lib/web_ui/lib/src/engine/app_bootstrap.dart
@@ -40,30 +40,17 @@
       // This is a convenience method that lets the programmer call "autoStart"
       // from JavaScript immediately after the main.dart.js has loaded.
       // Returns a promise that resolves to the Flutter app that was started.
-      autoStart: allowInterop(() {
-        return Promise<FlutterApp>(allowInterop((
-          PromiseResolver<FlutterApp> resolve,
-          PromiseRejecter _,
-        ) async {
-          await autoStart();
-          // Return the App that was just started
-          resolve(_prepareFlutterApp());
-        }));
-      }),
+      autoStart: allowInterop(() => futureToPromise(() async {
+        await autoStart();
+        // Return the App that was just started
+        return _prepareFlutterApp();
+      }())),
       // Calls [_initEngine], and returns a JS Promise that resolves to an
       // app runner object.
-      initializeEngine: allowInterop(([JsFlutterConfiguration? configuration]) {
-        // `params` coming from Javascript may be used to configure the engine intialization.
-        // The internal `initEngine` function must accept those params.
-        return Promise<FlutterAppRunner>(allowInterop((
-          PromiseResolver<FlutterAppRunner> resolve,
-          PromiseRejecter _,
-        ) async {
-          await _initializeEngine(configuration);
-          // Return an app runner object
-          resolve(_prepareAppRunner());
-        }));
-      }),
+      initializeEngine: allowInterop(([JsFlutterConfiguration? configuration]) => futureToPromise(() async {
+        await _initializeEngine(configuration);
+        return _prepareAppRunner();
+      }()))
     );
   }
 
@@ -77,7 +64,7 @@
       ) async {
         await _runApp();
         // Return the App that was just started
-        resolve(_prepareFlutterApp());
+        resolve.resolve(_prepareFlutterApp());
       }));
     }));
   }
diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
index 9f413f7..6168241 100644
--- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
+++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
@@ -176,9 +176,9 @@
 @staticInterop
 class SkWebGLContextOptions {
   external factory SkWebGLContextOptions({
-    required int antialias,
+    required double antialias,
     // WebGL version: 1 or 2.
-    required int majorVersion,
+    required double majorVersion,
   });
 }
 
@@ -1362,7 +1362,8 @@
 @JS('window.flutterCanvasKit.Path')
 @staticInterop
 class SkPath {
-  external factory SkPath([SkPath? other]);
+  external factory SkPath();
+  external factory SkPath.from(SkPath other);
 }
 
 extension SkPathExtension on SkPath {
diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart
index d0fc7a3..ff9d829 100644
--- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart
+++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart
@@ -325,7 +325,7 @@
           // Default to no anti-aliasing. Paint commands can be explicitly
           // anti-aliased by setting their `Paint` object's `antialias` property.
           antialias: _kUsingMSAA ? 1 : 0,
-          majorVersion: webGLVersion,
+          majorVersion: webGLVersion.toDouble(),
         ),
       ).toInt();
 
diff --git a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart
index 50a9ce5..1584b46 100644
--- a/lib/web_ui/lib/src/engine/js_interop/js_loader.dart
+++ b/lib/web_ui/lib/src/engine/js_interop/js_loader.dart
@@ -54,7 +54,7 @@
 /// [JsFlutterConfiguration] comes from `../configuration.dart`. It is the same
 /// object that can be used to configure flutter "inline", through the
 /// (to be deprecated) `window.flutterConfiguration` object.
-typedef InitializeEngineFn = Promise<FlutterAppRunner?> Function([JsFlutterConfiguration?]);
+typedef InitializeEngineFn = Promise<FlutterAppRunner> Function([JsFlutterConfiguration?]);
 
 /// Typedef for the `autoStart` function that can be called straight from an engine initializer instance.
 /// (Similar to [RunAppFn], but taking no specific "runApp" parameters).
diff --git a/lib/web_ui/lib/src/engine/js_interop/js_promise.dart b/lib/web_ui/lib/src/engine/js_interop/js_promise.dart
index 45f3f3b..9a7f9ca 100644
--- a/lib/web_ui/lib/src/engine/js_interop/js_promise.dart
+++ b/lib/web_ui/lib/src/engine/js_interop/js_promise.dart
@@ -6,18 +6,39 @@
 library js_promise;
 
 import 'package:js/js.dart';
+import 'package:js/js_util.dart' as js_util;
+
+@JS()
+@staticInterop
+class PromiseResolver<T extends Object?> {}
+
+extension PromiseResolverExtension<T extends Object?> on PromiseResolver<T> {
+  void resolve(T result) => js_util.callMethod(this, 'call', <Object>[this, if (result != null) result]);
+}
+
+@JS()
+@staticInterop
+class PromiseRejecter {}
+
+extension PromiseRejecterExtension on PromiseRejecter {
+  void reject(Object? error) => js_util.callMethod(this, 'call', <Object>[this, if (error != null) error]);
+}
 
 /// Type-safe JS Promises
 @JS('Promise')
 @staticInterop
-abstract class Promise<T> {
+abstract class Promise<T extends Object?> {
   /// A constructor for a JS promise
   external factory Promise(PromiseExecutor<T> executor);
 }
 
 /// The type of function that is used to create a Promise<T>
-typedef PromiseExecutor<T> = void Function(PromiseResolver<T> resolve, PromiseRejecter reject);
-/// The type of function used to resolve a Promise<T>
-typedef PromiseResolver<T> = void Function(T result);
-/// The type of function used to reject a Promise (of any <T>)
-typedef PromiseRejecter = void Function(Object? error);
+typedef PromiseExecutor<T extends Object?> = void Function(PromiseResolver<T> resolve, PromiseRejecter reject);
+
+Promise<T> futureToPromise<T extends Object>(Future<T> future) {
+  return Promise<T>(allowInterop((PromiseResolver<T> resolver, PromiseRejecter rejecter) {
+    future.then(
+      (T value) => resolver.resolve(value),
+      onError: (Object? error) => rejecter.reject(error));
+  }));
+}
diff --git a/lib/web_ui/lib/src/engine/navigation/history.dart b/lib/web_ui/lib/src/engine/navigation/history.dart
index bbee4c8..0cc335c 100644
--- a/lib/web_ui/lib/src/engine/navigation/history.dart
+++ b/lib/web_ui/lib/src/engine/navigation/history.dart
@@ -145,7 +145,7 @@
     if (_hasSerialCount(currentState)) {
       final Map<dynamic, dynamic> stateMap =
           currentState! as Map<dynamic, dynamic>;
-      return stateMap['serialCount'] as int;
+      return (stateMap['serialCount'] as double).toInt();
     }
     return 0;
   }