Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

yjbanov
Copy link
Contributor

@yjbanov yjbanov commented Jun 19, 2020

Description

This upgrades the dart:_engine code to null-safe Dart.

Notable changes:

  • Apply the new syntax (?, !, etc)
  • Implicit downcasts become explicit (required by the new language)
  • Disable dart2js inlining for tests for better stack traces
  • CSS attributes are no longer nullable => changed to assigning empty string instead of null
  • Changed html.window.navigator.clipboard?.writeText != null and html.window.navigator.clipboard?.readText != null to just html.window.navigator.clipboard != null because the tear-offs are never null.
  • Unimplemented non-null API that used to return null now throws UnsupportedError.
  • PathMetrics iterators throw RangeError instead of returning null (matches mobile behavior).
  • Refactor compositor/rasterizer.dart and compositor/surface.dart to initialize HtmlViewEmbedder upon construction so that it can be final and non-null.
  • Throw errors when CanvasKit fails to construct a GL surface, instead of just printing to window.console (this removes many null situations).
  • Replace List<Conic> with _ConicPair as temporary storage of results (NNBD does not support fixed-capacity lists).
  • Converted some constructors to factories so that final fields can be immediately initialized to non-null values as opposed to lazy initializing them (e.g. WriteBuffer, SurfaceCanvas)
  • EngineLineMetrics.withText uses bogus values for unsupported fields
  • Factories no longer return null (e.g. factory AutofillInfo.fromFrameworkMessage). This is a new language requirement.
  • Fixes an issue with getBoxesForRange in RTL mode (see paragraph_test.dart)

How to review this PR

  • This PR touches every file in the dart:_engine. It is not practical for one person to carefully review all of it. Instead, each reviewer is assigned a subset of files (although do feel free to comment on anything). The assignments are tracked in this spreadsheet: https://docs.google.com/spreadsheets/d/1Efar1J6eDARoeDlDI4qXdoldJuxUcMUeLpXpu3gQDMA/edit?pli=1#gid=180643056
  • The PR does not fix all nullability issues. It is not practical to address them all in a PR of this size. If you see places where something should be non-null but isn't, please file an issue so we remember to fix this in a smaller follow-up PR. The reverse is not true, however. If something has been make non-null where it should be nullable could lead to a bug, so please comment on that.

Related Issues

Fixes flutter/flutter#58811

Copy link
Contributor

@ferhatb ferhatb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First batch of comments.

Copy link
Contributor

@ferhatb ferhatb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments Batch2

@@ -22,7 +22,7 @@ class HoudiniCanvas extends EngineCanvas with SaveElementStackTracking {
/// where this canvas paints.
///
/// Painting outside the bounds of this rectangle is cropped.
final ui.Rect bounds;
final ui.Rect? bounds;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why nullable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we kill HoudiniCanvas until we're ready for a proper investigation? Not sure if it's worth maintaining it with no tests and users.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please go ahead.

Copy link
Contributor

@mdebbar mdebbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great effort! Thank you so much for working on it.

I'm still not done with the review, but wanted to submit the comments I have so far. All my comments are things we can iterate on later, not blockers.


/// Returns the [OperatingSystem] the current browsers works on.
///
/// This is used to implement operating system specific behavior such as
/// soft keyboards.
OperatingSystem get operatingSystem {
OperatingSystem? get operatingSystem {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, this should never return null. debugOperatingSystemOverride is returned only if it's non-null. And _detectOperatingSystem() returns a non-nullable.

Maybe we need the same trick you did in line 45?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return debugBrowserEngineOverride;
}
return _browserEngine ??= _detectBrowserEngine();
return debugBrowserEngineOverride ?? (_browserEngine ??= _detectBrowserEngine());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required to make the analyzer happy? I think it's possible to infer from the old code that the result is always non-nullable. Is this a known issue or should we file one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is to satisfy the type inference. It's a known issue, but not easily solvable. Maybe sealed classes will help one day.

@@ -23,17 +23,17 @@ abstract class LocationStrategy {
ui.VoidCallback onPopState(html.EventListener fn);

/// The active path in the browser history.
String get path;
String? get path;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this is nullable? In the HashLocationStrategy it always returns a string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -60,7 +60,7 @@ class TestLocationStrategy extends LocationStrategy {
bool get withinAppHistory => _currentEntryIndex >= 0;

@override
void pushState(dynamic state, String title, String url) {
void pushState(dynamic state, String title, String? url) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nullable url here is probably what's causing multiple other things to be nullable (e.g. String? get path, etc). Let's make it non-nullable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -77,7 +77,7 @@ class TestLocationStrategy extends LocationStrategy {
}

@override
void replaceState(dynamic state, String title, String url) {
void replaceState(dynamic state, String title, String? url) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


static void initInstance(html.Element glassPaneElement) {
static void initInstance(html.Element? glassPaneElement) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

glassPaneElement should never be null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

_PointerDataCallback _callback;
PointerDataConverter _pointerDataConverter;
PointerDataConverter? _pointerDataConverter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find a situation where this can be null. It's always initialized in the constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -71,7 +71,7 @@ class Profiler {
return Profiler._instance ??= Profiler._();
}

static Profiler get instance {
static Profiler? get instance {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This never returns null. If _instance is null, it throws.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -147,8 +147,8 @@ class RulerManager {
/// The returned ruler is marked as hit so there's no need to do that
/// elsewhere.
@visibleForTesting
ParagraphRuler findOrCreateRuler(ParagraphGeometricStyle style) {
ParagraphRuler ruler = _rulers[style];
ParagraphRuler? findOrCreateRuler(ParagraphGeometricStyle style) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all cases, this function returns a ruler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

final String? _ellipsis;
final ui.Locale? _locale;

String? get _effectiveFontFamily {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is never null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@yjbanov yjbanov force-pushed the nnbd-migrate-web-engine branch from d9771b6 to 56ea6bb Compare June 22, 2020 16:56
@@ -66,7 +66,7 @@ abstract class EngineInputType {
html.HtmlElement createDomElement() => html.InputElement();

/// Given a [domElement], set attributes that are specific to this input type.
void configureInputMode(html.HtmlElement domElement) {
void configureInputMode(html.HtmlElement? domElement) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When calling this method, dom_element should not be null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -75,7 +75,7 @@ abstract class EngineInputType {
// keyboard shows up.
if (operatingSystem == OperatingSystem.iOs ||
operatingSystem == OperatingSystem.android) {
domElement.setAttribute('inputmode', inputmodeAttribute);
domElement!.setAttribute('inputmode', inputmodeAttribute!);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dom_element should not be null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -14,7 +14,7 @@ part of engine;
abstract class EngineInputType {
const EngineInputType();

static EngineInputType fromName(String name) {
static EngineInputType fromName(String? name) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name shouldn't be null. It always get defaulted to TextInputType.text on the framework side.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@yjbanov
Copy link
Contributor Author

yjbanov commented Jun 23, 2020

I think responded to all the comments (at least those I was able to find). PTAL! This is no longer a draft. While I'm still testing manually, this is good to go.

@yjbanov yjbanov force-pushed the nnbd-migrate-web-engine branch from 231bb98 to a21cf7e Compare June 23, 2020 23:52
@@ -49,7 +49,7 @@ class SemanticsHelper {
return _semanticsEnabler.shouldEnableSemantics(event);
}

html.Element prepareAccesibilityPlaceholder() {
html.Element? prepareAccesibilityPlaceholder() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prepareAccesibilityPlaceholder always returns a value so this is never null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -189,12 +189,12 @@ class DesktopSemanticsEnabler extends SemanticsEnabler {
}

@override
html.Element prepareAccesibilityPlaceholder() {
_semanticsPlaceholder = html.Element.tag('flt-semantics-placeholder');
html.Element? prepareAccesibilityPlaceholder() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is never null (related to the previous comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

AutofillInfo.fromFrameworkMessage(focusedElementAutofill);
final Map<String, html.HtmlElement> elements = <String, html.HtmlElement>{};
final Map<String, AutofillInfo> items = <String, AutofillInfo>{};
final Map<String?, html.HtmlElement> elements = <String?, html.HtmlElement>{};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing something, I don't understand the usage of String? as a map key.

Does that mean the key is nullable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Most of the conversion is syntactic. Prior to null safety everything was nullable. The goal of this PR is to convert to the new syntax (i.e. add ? to what's nullable). Converting to non-null is nice-to-have, but it's not realistic to clean up everything in one PR. I expect most of the actual refactoring will happen in many small PRs following this one.

List<StreamSubscription<html.Event>> subscriptions =
<StreamSubscription<html.Event>>[];
keys.forEach((String key) {
final html.Element element = elements[key];
keys.forEach((String? key) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question. Why map can have null keys?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


/// Unique value set by the developer.
///
/// Used as id of the text field.
final String uniqueIdentifier;
final String? uniqueIdentifier;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is autofill info, it means this value is always sent. Therefore this should not be null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


/// Attribute used for autofill.
///
/// Used as a guidance to the browser as to the type of information expected
/// in the field.
/// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
final String hint;
final String? hint;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above comment: "If there is autofill info, it means this value is always sent. Therefore this should not be null."

@yjbanov yjbanov force-pushed the nnbd-migrate-web-engine branch from a21cf7e to 8bb4e61 Compare June 24, 2020 18:11
}

@override
set strokeMiterLimit(double value) {
assert(value != null);
throw UnsupportedError('SurfacePaint.strokeMiterLimit');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keeps assert and add TODO, there is already an issue i believe. Otherwise it would be breaking change (some apps using it today would start failing).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -838,9 +840,9 @@ class SurfacePath implements ui.Path {
(2 * t1 * tprime * cpY) +
(t1 * t1 * y2);
// Expand bounds.
minX = math.min(minX, extremaX);
minX = math.min(minX, extremaX as double);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion change tprime/extremaX/Y to final double and remove as. Here and below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, although it seems as double is a noop in dart2js. It compiles to:

  extremaX = t13 * curX + t14 * cpX + t12 * x2;
  extremaY = t13 * curY + t14 * cpY + t12 * y2;
  minX = Math.min(minX, extremaX);
  maxX = Math.max(maxX, extremaX);
  minY = Math.min(minY, extremaY);
  maxY = Math.max(maxY, extremaY);

);

if (frameSize.isEmpty) {
if (layerTree.frameSize.isEmpty) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this never sets the frameSize on layerTree

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to de-null frameSize I changed the initialization sequence a little. frameSize is now final non-null field on LayerTree, so it's guaranteed to be available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also removed frameSize from Rasterizer as it is available in the LayerTree, which Rasterizer has access to already.

@@ -27,14 +27,14 @@ class EngineWindow extends ui.Window {

@override
double get devicePixelRatio => _debugDevicePixelRatio != null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be double get devicePixelRatio => _debugDevicePixelRatio ?? browserDevicePixelRatio;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@yjbanov yjbanov force-pushed the nnbd-migrate-web-engine branch from d78ee38 to 43882d0 Compare June 26, 2020 16:26
@yjbanov yjbanov merged commit de74f8a into flutter:master Jun 26, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 29, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 29, 2020
jonahwilliams pushed a commit to flutter/flutter that referenced this pull request Jun 29, 2020
* 1ae95f7 Roll Skia from 318afe66e699 to 63a0a758ce14 (4 revisions) (flutter/engine#19335)

* b1b9469 Manual roll of Dart e24733ebd1...63cf56d925 (flutter/engine#19337)

* de68a7f Roll Skia from 63a0a758ce14 to f123f06aabd6 (9 revisions) (flutter/engine#19336)

* 220a831 Move fuchsia/scenic integration behind #define (flutter/engine#19003)

* de74f8a migrate web engine implementation to null-safe Dart (flutter/engine#19172)

* 4cd3ec0 Fix broken mac/fuchsia compiles (flutter/engine#19339)

* 77e9f94 Roll Dart SDK from e24733ebd16c to 243ad5427564 (5 revisions) (flutter/engine#19338)

* 4333fc3 Roll Dart SDK from 243ad5427564 to 7fc61e77e225 (5 revisions) (flutter/engine#19342)

* b3cfbd2 Roll Fuchsia Mac SDK from YGK_M... to l3tHO... (flutter/engine#19343)

* a28b7f0 Implement onDisplayPlatformView (flutter/engine#19344)

* 1a4f38f Roll Dart SDK from 7fc61e77e225 to 871f0ee31eb0 (4 revisions) (flutter/engine#19346)

* 3d61564 Roll Fuchsia Linux SDK from _d0dW... to Y_dK2... (flutter/engine#19347)

* 727a38d Roll Fuchsia Mac SDK from l3tHO... to SuveI... (flutter/engine#19348)

* ccfa0e7 Roll Fuchsia Linux SDK from Y_dK2... to lgSTC... (flutter/engine#19349)

* 2ff740e Roll Dart SDK from 871f0ee31eb0 to f91547d6dd45 (1 revision) (flutter/engine#19350)

* 692dfb3 update compilation rules for null-safety (flutter/engine#19386)

* 729ca5e Roll Fuchsia Linux SDK from lgSTC... to ScRia... (flutter/engine#19389)
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
* 1ae95f7 Roll Skia from 318afe66e699 to 63a0a758ce14 (4 revisions) (flutter/engine#19335)

* b1b9469 Manual roll of Dart e24733ebd1...63cf56d925 (flutter/engine#19337)

* de68a7f Roll Skia from 63a0a758ce14 to f123f06aabd6 (9 revisions) (flutter/engine#19336)

* 220a831 Move fuchsia/scenic integration behind #define (flutter/engine#19003)

* de74f8a migrate web engine implementation to null-safe Dart (flutter/engine#19172)

* 4cd3ec0 Fix broken mac/fuchsia compiles (flutter/engine#19339)

* 77e9f94 Roll Dart SDK from e24733ebd16c to 243ad5427564 (5 revisions) (flutter/engine#19338)

* 4333fc3 Roll Dart SDK from 243ad5427564 to 7fc61e77e225 (5 revisions) (flutter/engine#19342)

* b3cfbd2 Roll Fuchsia Mac SDK from YGK_M... to l3tHO... (flutter/engine#19343)

* a28b7f0 Implement onDisplayPlatformView (flutter/engine#19344)

* 1a4f38f Roll Dart SDK from 7fc61e77e225 to 871f0ee31eb0 (4 revisions) (flutter/engine#19346)

* 3d61564 Roll Fuchsia Linux SDK from _d0dW... to Y_dK2... (flutter/engine#19347)

* 727a38d Roll Fuchsia Mac SDK from l3tHO... to SuveI... (flutter/engine#19348)

* ccfa0e7 Roll Fuchsia Linux SDK from Y_dK2... to lgSTC... (flutter/engine#19349)

* 2ff740e Roll Dart SDK from 871f0ee31eb0 to f91547d6dd45 (1 revision) (flutter/engine#19350)

* 692dfb3 update compilation rules for null-safety (flutter/engine#19386)

* 729ca5e Roll Fuchsia Linux SDK from lgSTC... to ScRia... (flutter/engine#19389)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make dart:_engine (web engine implementation) null safe
7 participants