-
Notifications
You must be signed in to change notification settings - Fork 6k
take web_ui to null safety #19027
take web_ui to null safety #19027
Conversation
vsmenon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
| // TODO(yjbanov): The code in this file was temporarily moved to lib/web_ui/lib/ui.dart | ||
| // during the NNBD migration so that `dart:ui` does not have to export | ||
| // `dart:_engine`. NNBD does not allow exported non-migrated libraries | ||
| // from migrated libraries. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@leafpetersen - is this a bug or an intended restriction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was intentional. We could remove the restriction, but I was aiming to have the property that opted in packages had no legacy types in their public interface, so that if you migrated relative to an opted in package you could be confident that you were done.
|
|
||
| void _setLabel(html.Element element) { | ||
| if (semanticsObject.hasLabel) { | ||
| print('>>> semanticsObject.label = ${semanticsObject.label}'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And a few more below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a draft PR. I exported it early to help reproduce dart-lang/sdk#42324. Sorry if it wasn't clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleaned it up.
| /// Return value should be null on success, and a string error message on | ||
| /// failure. | ||
| typedef Callbacker<T> = String Function(Callback<T> callback); | ||
| typedef Callbacker<T> = String/*?*/ Function(Callback<T> callback); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean to keep comment syntax here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now. This PR only migrates dart:ui. dart:_engine will follow next.
| final T item = _queue.removeFirst(); | ||
| if (_dropItemCallback != null) { | ||
| _dropItemCallback(item); | ||
| _dropItemCallback!(item); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could replace if block with:
_dropItemCallback?.call(item);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| engine.AssetManager/*?*/ _assetManager; | ||
| engine.FontCollection _fontCollection; | ||
| engine.AssetManager? _assetManager; | ||
| engine.FontCollection? _fontCollection; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a late?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't been lucky with late yet, but maybe I'm not trying hard enough. The issue is most of our initialization patterns rely on null checks, e.g. if (foo == null) initializeFoo();. However, late non-null variables cannot be null checked.
It's OK for this PR to be incomplete. The goal is to move to the new syntax and to have a more or less correct public API surface. Internal parts can be revisited later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed flutter/flutter#59371 to revisit this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks to me like it could be late final engine.FontCollection _fontCollection = engine.FontCollection();
| SkiaFontCollection skiaFontCollection; | ||
|
|
||
| /// Initializes [skiaFontCollection]. | ||
| void ensureSkiaFontCollectionInitialized() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once this file is opted in, can this become late SkiaFontCollection = skiaFontCollection? Maybe final if it doesn't get reset?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully. Filed flutter/flutter#59371 to revisit this.
lib/web_ui/lib/src/ui/canvas.dart
Outdated
| void clipRect(Rect/*!*/ rect, | ||
| {ClipOp clipOp/*!*/ = ClipOp.intersect, bool/*!*/ doAntiAlias = true}); | ||
| void clipRect(Rect rect, | ||
| {ClipOp clipOp/*!*/ = ClipOp.intersect, bool doAntiAlias = true}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover comment syntax?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. The comment syntax was on the variable, not on the type, so the migration tool missed it. Fixed.
| /// * [BlendMode], which discusses the use of [Paint.blendMode] with | ||
| /// [saveLayer]. | ||
| void saveLayer(Rect/*?*/ bounds, Paint/*!*/ paint); | ||
| void saveLayer(Rect? bounds, Paint paint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are you validating that these APIs migrated to the same types as the other dart:ui?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed api_confrom_test.dart, but I'm not sure how to validate parameters. Can't find the right fields in the AST nodes 🤔 (maybe just tired at the end of the week)
|
|
||
| dependencies: | ||
| meta: 1.1.8 | ||
| meta: ^1.1.8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you still need meta?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we have tests and dev tools using it.
| } | ||
| expect(semantics().semanticsEnabled, true); | ||
| }); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming that if tests pass they were migrated correctly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course 😎
jonahwilliams
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
(But not to CI) |
| static Rect/*?*/ lerp(Rect/*?*/ a, Rect/*?*/ b, double/*!*/ t) { | ||
| static Rect? lerp(Rect? a, Rect? b, double t) { | ||
| assert(t != null); | ||
| if (b == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I just have to say - how cool is it that this code just worked with no changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did change this function in a previous PR to assist with type inference: f581f42#diff-3afaf9265618b9fee97b10a7de58cc76
But it's still pretty cool that despite both a and b being nullable, there are no ! in the body of the function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I almost asked why it wasn't written the way it was pre-refactor... :)
If avoiding the extra instructions is important, you could write it as:
if (a == null) return (b == null) ? null : b * t;
if (b == null) return (a == null) ? null : a * (1.0 - t)
return ....
I also noticed that there were places where this was called with what looked like definitely non-nullable arguments, which made me wonder whether it was worth having a specialized version. But I have no idea which pieces of this are perf sensitive, so...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have an annotation instructing the compiler to specialize automatically, similar to Scala's @specialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider filing a feature request for @specialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: dart-lang/sdk#42361
lib/web_ui/lib/src/ui/lerp.dart
Outdated
| a ??= 0.0; | ||
| b ??= 0.0; | ||
| return a + (b - a) * t; | ||
| return a + (b - a) * t as double?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just as double. The result can't be null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stereotype441 good feedback for the tool?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| callback(codec.encodeSuccessEnvelope(null)); | ||
| } | ||
|
|
||
| // TODO(yjbanov): remove _Callback, _Callbacker, and _futurize. They are here only |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this bug just got fixed in master, but probably hasn't rolled to you yet.
I keep forgetting that non-nullable experiment in analysis_options.yaml is not enough. You also have to pass it to |
8822517 to
f0259c0
Compare
| await chromeDriverInstaller.install(alwaysInstall: true); | ||
| // TODO(yjbanov): remove this dynamic hack when chromeDriverInstaller.install returns Future<void> | ||
| // https://github.com/flutter/flutter/issues/59376 | ||
| dynamic installationFuture = chromeDriverInstaller.install(alwaysInstall: true) as dynamic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
lib/web_ui/lib/src/ui/geometry.dart
Outdated
| /// | ||
| /// The `center` argument is assumed to be an offset from the origin. | ||
| Rect.fromCenter({ Offset center/*!*/, double/*!*/ width, double/*!*/ height }) : this.fromLTRB( | ||
| Rect.fromCenter({ required Offset center/*!*/, required double width, required double height }) : this.fromLTRB( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stray /*!*/ ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| static Rect/*?*/ lerp(Rect/*?*/ a, Rect/*?*/ b, double/*!*/ t) { | ||
| static Rect? lerp(Rect? a, Rect? b, double t) { | ||
| assert(t != null); | ||
| if (b == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider filing a feature request for @specialized.
| /// [Locale] objects. | ||
| String/*!*/ get languageCode => _deprecatedLanguageSubtagMap[_languageCode] ?? _languageCode; | ||
| final String/*!*/ _languageCode; | ||
| String get languageCode => _deprecatedLanguageSubtagMap[_languageCode] ?? _languageCode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the value type of _deprecatedLanguageSubtagMap be String?? Or does the ? get tacked onto e.g. the return type of operator[]?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, operator[] always returns nullable type, no matter what type arguments the map has.
|
Description
Convert the web version of
dart:uito null safety syntax.Related Issues
flutter/flutter#53661