-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Analyzer won't promote type of member variables #34480
Comments
I believe that this is working as specified. The specification explicitly defines type promotion to apply to local variables and formal parameters; fields are not promoted. |
I don't doubt that it's working as specified, I was asking for the specification to be changed. :-) |
Might I suggest we track all requests for enhanced type promotion in one place/bug (i.e. #25565 or perhaps a new thread on Consider: abstract class X {
Object get id;
}
class Y extends X {
@override
Object get id => 'Y';
void newMethod() {
if (this.name is String) {
print(name.toUpperCase());
}
}
}
class Z extends Y {
var _returnString = true;
// Evil, but completely valid in the language.
@override
Object get id {
if (_returnString) {
_returnString = false;
return 'Hello';
}
_returnString = true;
return 5;
}
}
void main() {
// Error: Type int does not have an instance method 'toUpperCase()'.
Z().newMethod();
} To be able to promote class-level members, we would need either:
For example, for the above we could either: sealed class Y extends X { ... } or class Y extends X {
@override
final Object get id => 'Y';
} ... that would prevent the patterns in |
The previous comment seems to be about getters, which (as noted in that comment) you can't promote sanely. The original comment was only about member variables (fields), in a case where you statically prove that there's no possibility of shenanigans. |
That unfortunately is not true. Originally @leafpetersen and @vsmenon tried to make fields non-virtual by default (see class X {
final x = 'Hello';
}
class Y extends X {
bool _returnNull = true;
get x => {
_returnNull = !returnNull;
return _returnNull ? null : 'Hello';
}
}
void main() {
X x = Y();
if (x.x is String) {
print(x.x is String); // false
}
} Even then, it isn't clear how this would work for class X {
final x = 'Hello';
}
class Y extends X {
bool _returnNull = false;
get x => {
_returnNull = !returnNull;
return _returnNull ? null : 'Hello';
}
}
void main() {
X x = Y();
if (x.x is String) {
print(x.x is String); // false
}
} |
I know @eernstg had a very informal proposal to help here though, something like: void main() {
X x = Y();
// If x.x is a String, assign it to a new variable "localX"
if (x.x is String : localX) {
print(localX is String); // true
}
} |
Yes, the example @matanlurey gives in #34480 (comment) is the germane one (in fact, instead of The two options that we might consider are to automatically insert runtime checks on each use, or to provide better syntax for binding a new promoted variable in the scope of the promotion. |
I agree that in the example above, with a public member, it can't be proved, but in the original example the field is private, which means the analyzer has all the information it needs to determine whether it can be promoted. |
Yes, this seems like somewhere the specs/tools could enhance today. I do admit though that would be very confusing to users - for example making a private variable public would be a breaking change in this case. |
Worse, adding a mock of an interface would be a breaking change. That is, as @Hixie notes, the analyzer could notice that a private field is never implemented by a getter and allow promotion. But now you add a mock that implements the field as a getter, and some completely unrelated code breaks because promotion becomes disabled. |
@leafpetersen Ok, we could do private |
The following code results in
The getter 'x' isn't defined for the class 'A' • test.dart:13:17 • undefined_getter
even though it can be statically proved that it is fine (since nothing can change the type of_a
before we access the getterx
).The text was updated successfully, but these errors were encountered: