Skip to content

Flow analysis could handle final variables with assignments better #1721

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

Closed
stereotype441 opened this issue Jul 2, 2021 · 9 comments
Closed
Labels
feature Proposed language feature that solves one or more problems flow-analysis Discussions about possible future improvements to flow analysis

Comments

@stereotype441
Copy link
Member

Consider the following code (adapted from discussion in #1247):

bool f(bool b) {
  final num a; // (1)
  if (b) {
    a = 0; // (2)
  } else {
    a = 0.5; // (3)
  } // (4)
  bool Function() g;
  if (a is int) { // (5)
    g = () => a.isEven; // (6)
  } else {
    g = () => false;
  }
  return g();
}

This has an error at the line marked (6): The getter 'isEven' isn't defined for the type 'num'.

If the lines from (1) to (4) are replaced with:

  final num a = b ? 0 : 0.5;

then no error occurs.

What's happening is that flow analysis sees the assignments to a on lines (2) and (3), and conservatively assumes that they could happen at any time, including between the time of the test at (5) and the usage at (6). So it disables promotion. But this is nonsense, because a is a final variable, therefore at the time of the test on line (5), it is guaranteed to be already assigned (otherwise line (5) would have had an error), and thus no further assignments to it can occur. So it should be safe to promote.

It should be safe to alter flow analysis so that assignments do not defeat promotion if the variable assigned to is final. This will work even for late final variables, because such variables are still guaranteed not to be assigned to more than once (the only difference is that the checking is done at runtime rather than statically).

@stereotype441 stereotype441 added feature Proposed language feature that solves one or more problems flow-analysis Discussions about possible future improvements to flow analysis labels Jul 2, 2021
@stereotype441
Copy link
Member Author

@renatoathaydes FYI

@srawlins
Copy link
Member

srawlins commented Jul 2, 2021

Related to, maybe identical, #1536

@stereotype441
Copy link
Member Author

Related to, maybe identical, #1536

Good point, @srawlins. IMHO they're not identical because #1536 is about a variable that's definitely not final. But they're definitely related bugs. Hopefully we can think of a fix that would address both of them.

@renatoathaydes
Copy link

@stereotype441 the if in the assignment is not necessary, this simplified version of the code still won't compile:

bool f(bool b) {
  final num a; // (1)
  a = 2;
  bool Function() g;
  if (a is int) { // (5)
    g = () => a.isEven; // (6)
  } else {
    g = () => false;
  }
  return g();
}

@Levi-Lesches
Copy link

Levi-Lesches commented Jul 2, 2021

Well as long as we're playing code golf, I'll join in 😁

void f(bool b) {
  final num a;
  a = 2;
  if (a is int) {
    final g = () => a.isEven; // error: isEven isn't defined for num
  }
}

@stereotype441
Copy link
Member Author

Well as long as we're playing code golf, I'll join in 😁

@Levi-Lesches Haha, challenge accepted! How about:

f(){final Object a;a=2;a is int?()=>-a:0;}

More seriously, @renatoathaydes is right, the if in the assignment is not an essential part of this bug 😃

@renatoathaydes
Copy link

renatoathaydes commented Jul 2, 2021

Related to, maybe identical, #1536

That issue shows that people expect even non-final local variables to work in such cases because that's safe (if the variable is not re-assigned anywhere). I wrote a comment in that issue showing how that works in Kotlin (basically using the concept from Java of effectively final).

@Levi-Lesches exactly, even the other if was unecessary. But the point was that Dart behaves particularly badly because it distinguishes between:

final num a;
a = 1;

and

final num a = 1;

@eernstg
Copy link
Member

eernstg commented Jul 5, 2021

It's an even better point if we can treat

  final num a;
  if (b) {
    ... // Do arbitrary stuff, just nothing about `a`.
    a = 0;
    ... // Do arbitrary stuff, just nothing about `a`.
  } else {
    ... // Do arbitrary stuff, just nothing about `a`.
    a = 0.5;
    ... // Do arbitrary stuff, just nothing about `a`.
  }

and

  final num a = b ? 0 : 0.5;

as equivalent, with respect to promotions of a.

copybara-service bot pushed a commit to dart-lang/sdk that referenced this issue Oct 19, 2021
The fields `isFinal` and `isLate` are moved to the `Var` class.  This
should allow greater flexibility when experimenting with possible
changes in promotion behavior for final and late variables.

Bug: dart-lang/language#1721
Change-Id: I3a328566b4a55244ca76c41da6e362066118d283
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217261
Reviewed-by: Konstantin Shcheglov <[email protected]>
Commit-Queue: Paul Berry <[email protected]>
copybara-service bot pushed a commit to dart-lang/sdk that referenced this issue Oct 16, 2024
… for final vars.

Tests for the issue dart-lang/language#1721.

Promotions should happen for final variables because they are assigned and won't be re-assigned by the time they're evaluated. In a conservative join, promotions should not be cancelled for final variables.

Bug: dart-lang/language#1721
Change-Id: Ibf29f42052a054424f7cef1075d1f67203f62c06
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/390340
Reviewed-by: Paul Berry <[email protected]>
Commit-Queue: Kallen Tu <[email protected]>
copybara-service bot pushed a commit to dart-lang/sdk that referenced this issue Oct 22, 2024
Promotions should happen for final variables because they are assigned and won't be re-assigned by the time they're evaluated. In a conservative join, promotions should not be cancelled for final variables.

Language tests made in https://dart-review.googlesource.com/c/sdk/+/390340.

Bug: dart-lang/language#1721
Change-Id: I7bb577a694ddb5572a28884de70bd8c5b68e3c25
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/390803
Reviewed-by: Chloe Stefantsova <[email protected]>
Reviewed-by: Paul Berry <[email protected]>
Commit-Queue: Kallen Tu <[email protected]>
@kallentu
Copy link
Member

dart-lang/sdk@47d5502 addresses this behaviour (although, currently under the inference-update-4 flag). Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems flow-analysis Discussions about possible future improvements to flow analysis
Projects
None yet
Development

No branches or pull requests

6 participants