-
Notifications
You must be signed in to change notification settings - Fork 29.1k
migrate foundation to nullsafety #61188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
1416458
to
12c3513
Compare
packages/flutter/lib/foundation.dart
Outdated
@@ -2,7 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style license that can be | |||
// found in the LICENSE file. | |||
|
|||
// @dart = 2.8 | |||
// @dart = 2.9 |
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 probably how this should be landed is by bumping the min sdk version in the pubspec to be a 2.9 release, and removing the // @Dart comments in the opted in files entirely. @jakemac53 @jonahwilliams does that sound right?
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.
That sounds like an approach with less churn. Is 2.9 the null safety language version, or could that change?
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.
2.9 will not be the final null safety language version. It is likely, but not guaranteed that 2.10 will be the final null safety language version.
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.
okay, in that case we should definitely do it in the pubspec so there is only a single location, right?
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 prefered to explicitly use // @dart = 2.9
during the incremental migration for simple searchability. Once all framework is migrated I will remove it. Note that the pubspec.yaml sdk version is already pointing to 2.9.
Does it look good to you?
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.
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 we set it to 2.10 now?
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 we set it to 2.10 now?
You could try it, but I wouldn't really recommend it. You're more or less relying on undefined behavior in that case. It might just work, in which case it's probably fine, but it also might work in some places and not others, or suddenly stop working, or whatever.
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.
If this is really just about tracking which things are migrated, maybe consider just using some other arbitrary string to tag them? // @Dart = migrated ?
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'll remove it directly. I don't use it too much now.
99a4718
to
f032430
Compare
@@ -5,3 +5,7 @@ include: ../analysis_options.yaml | |||
analyzer: | |||
enable-experiment: | |||
- non-nullable | |||
errors: | |||
always_require_non_null_named_parameters: false # not needed with nnbd | |||
void_checks: false # issues with nnbd |
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.
Is there an issue on file that we could link from 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.
link to issue added.
errors: | ||
always_require_non_null_named_parameters: false # not needed with nnbd | ||
void_checks: false # issues with nnbd | ||
unnecessary_null_comparison: false |
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.
Why do we turn this one off?
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 needed to avoid warning on null assertion on non-nullable variable. For instance:
void m(String s) {
assert(s != null);
}
This could change with #61042
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.
If the variable itself is already non-nullable, why do we still need the assert? Wouldn't we want to clean that up and remove it?
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.
Either way, It would probably be good to have a comment on this line explaining why we turn this off.
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.
If the variable itself is already non-nullable, why do we still need the assert?
At first glance, it might seem sensible to remove the assertion on the grounds that c can no longer be null, but that's only true in strong mode. Flutter will have a long tail of users running in weak mode until Dart 3.0, and assertions like these are necessary to help prevent them from passing nulls to Flutter APIs.
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.
Thanks for the context and adding it as a comment.
assert(() { | ||
optimizedValue = object.runtimeType.toString(); | ||
return true; | ||
}()); | ||
return optimizedValue; | ||
} | ||
|
||
/// Allows promotion of a variable to another type. |
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 feels like a strange thing to add to flutter's public API. Looks like it is only used in one file. Can we just add it as a private thing there? Or, instead of using promote, can you just do the following in the code:
num n = 42;
n = n as int;
n.isEven;
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 don't remind the issue but @Hixie suggested to add this 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.
Finally I removed this function for now.
@@ -29,7 +27,7 @@ import 'dart:collection'; | |||
class ObserverList<T> extends Iterable<T> { | |||
final List<T> _list = <T>[]; | |||
bool _isDirty = false; | |||
HashSet<T> _set; | |||
late final HashSet<T> _set = HashSet<T>(); |
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.
Why 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.
IIRC this will make the field lazy initialized.
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 won't do anything in this case (other than maybe make it slower to access). It allows you to (yourself) lazily initialize it but leave it as a non-nullable type.
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.
Sorry if this wasn't clear, but my question was meant as: "Why are we declaring this field as late? It seems unnecessary 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.
It was lazy before - I think there was a misunderstanding around what late
means. If assigning immediately it has no meaning @stereotype441 should we have a lint for this?
To restore the lazy behavior that existed before this would have to be a nullable field type, and you would have to restore the old logic.
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.
@jakemac53 that's not correct. late with an initializer means lazy.
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.
Now I am confused. What is the difference between those two lines?
late final int foo = 1;
final int bar = 1;
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.
Nothing, because you can't observe laziness with a value. But:
class A {
late final int foo = (() {print("hello"); return 1;})();
final int bar = (() {print("world"); return 1;})();
A();
}
void main() {
var a = A();
print("says");
a.foo;
}
outputs
world
says
hello
because a late
variable with an initializer only evaluates its initializer on first use.
cc @munificent this is something we're going to have to explain carefully.
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.
Thanks for the explanation!
int start = 0; | ||
int startForLengthCalculations = 0; | ||
bool addPrefix = false; | ||
int index = prefix.length; | ||
_WordWrapParseMode mode = _WordWrapParseMode.inSpace; | ||
int lastWordStart; | ||
int lastWordEnd; | ||
// TODO(a14n): use `late int lastWordStart;` |
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.
What's currently stopping us to do 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.
late
is a little dangerous for public member. I'm not sure the TODO is still relevant. I'll check.
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 am not sure I fully understand, lastWordStart
seems to be private to this method?
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.
comment removed. I added it to remind me that a lint could be done to use late
.
Note that force pushing destroys all pr comment history so please avoid that :). |
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
* migrate foundation to nullsafety * address review comments
* migrate foundation to nullsafety * address review comments
Description
NNBD migration for foundation
Related Issues
Tests
I added the following tests:
None
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.///
).flutter analyze --flutter-repo
) does not report any problems on my PR.Breaking Change
Did any tests fail when you ran them? Please read Handling breaking changes.