-
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
[dart devc] Pattern matching use same variable name cause unexpected behavior #54559
Comments
Drive-by comment (I'm working on the language, not on the implementation of compilation to JavaScript in any tool). @huanghui1998hhh, what's your configuration? With main() {
A.printString("hello world");
} Perhaps your issue should be classified as a DDC issue? Also, the kernel code looks as follows (but note that there may be differences between the kernel code generated for different backends):
It looks similar to your JavaScript code, but there may be some rules about the meaning of |
@eernstg the issue title indicates it's a Flutter Web debug mode - which means DDC. |
cc @nshahan |
Yes, this is a DDC issue. Maybe I should use tag |
Inspecting the kernel for this example shows that the shadowing |
Look deeper into the 'shadowing'. DDC could fix this by generating different JavaScript names for shadowed names, either avoiding shadowed names entirely, or doing some analysis to tell if the separate JavaScript names are needed to express the correct lookup in the generated code's scope structure. The Kernel printer could also disambiguate 'shadowing' by adding a suffix or other annotation to distinguish variables in nested scopes with the same name , e.g. using fooValue1 instead of fooValue for one of the variables. |
It is unfortunate that the lowering introduces was looks like a shadowing. I'll see if we can avoid this. |
There is a broader issue - the user program has two variables with the same name. I believe currently that the DDC generated code has a JavaScript scope model that is mostly in alignment with the Dart model, so the debug experience works. Johnni - what changes were you thinking of? The CFE should not change user variable names. It might be possible to rearrange the lowered code so that the scopes don't 'interleave' like in the Kernel snippet. Can that the scopes be arranged to be non-interleaved in the general case? /cc @annagrin |
I agree, there is shadowing present in the original source code and it would provide the most consistent user experience in the debugger if the shadowing still exists. Along with a change to where the hoisted variable is declared so that doesn't break the initialization of the synthetic variable. |
I've created https://dart-review.googlesource.com/c/sdk/+/345942 which fixes the problem created by the CFE: That a legal shadowing (old variable read before the new was declared) was turned into an illegal "shadowing" (the old variable read after the new was declared). The CL doesn't change the names of the variables, so the shadowing vs debugging must still be addressed. |
@johnniwinther Thanks for the quick fix! |
Thanks for the fix! :D Since you were looking for feedback on if this is worth being cherry-picked, I'd personally say yes, but probably only for 3.3. I'd like to encourage developers to use if-case more when needing type promotion of a field rather than shadowing a field with a local variable (dart-lang/site-www#5461), but I'm hesitant if this will be causing confusion for a few months. In most cases it makes sense to provide a more specific name, but when trying to type promote a field, many developers likely choose to use the same name. If it resulted in a compile-time error, I think it would be less important, but since it doesn't, I think this behavior could result in misconceptions, especially if they mostly develop or test their apps with debug web builds. |
In my opinion(as a Front-end developer), local variable still have some advantage. Sometimes, we may face the following situation, there have a lot of conditional control, so we have to use early return. So the if-case is not applicable. Maybe dart need something like |
@huanghui1998hhh Yep, I agree! If you want early return, a local variable is still necessary. See (and maybe react to) dart-lang/language#2537 for a potential solution to this :) Thanks for reporting this issue by the way! |
Using an if-case for promotion was not the issue causing a bug here. The bug occurs when using an if-case to introduce a new local variable that shadows another. This triggered the issue: String? fooValue = 'hello world';
if (fooValue case final String fooValue) {
print(fooValue);
} The issue is not triggered when the new variable doesn't shadow the earlier local: String? fooValue = 'hello world';
if (fooValue case final String newFooValue) {
print(newFooValue);
} Also, using a type match pattern without introducing any local variable does not trigger the issue either, while giving promotion where it is possible: class C {
final String? _fooValue = 'hello world';
void fn() {
if (_fooValue case String()) {
print(_fooValue);
}
}
} Does that change your opinion of the need to get this fix in 3.3? |
@nshahan Ahh I see! I didn't realize this issue only occurred for local variables, not instance variables (fields). I also misspecified, sorry about that. I meant as a workaround when field promotion doesn't work. Because (for better or worse) many cases I've seen of using if-case as a workaround do shadow the field name. If it doesn't occur for fields, I'm definitely not as worried about it! It can always be reevaluated if more developers end up hitting this. Thanks for explaining :) |
Steps to reproduce
Create a flutter project and run flutter web on debug mode with this code:
And this is it's js result:
So it will not print
'hello world'
.The text was updated successfully, but these errors were encountered: