Skip to content
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

Using a late final variable as loop variable for for/in gives incorrect late errors #60359

Open
lrhn opened this issue Mar 19, 2025 · 2 comments
Labels
area-dart-model For issues related to conformance to the language spec in the parser, compilers or the CLI analyzer. model-flow Implementation of flow analysis in analyzer/cfe P3 A lower priority bug or feature request

Comments

@lrhn
Copy link
Member

lrhn commented Mar 19, 2025

Example:

void main() {
  late final int c;
  var ints = <int>[1];
  for (c in ints) {
    print(c);
  }
}

This code should be able to run without invalidating any late variable constraints.

The analyzer reports:

The late final local variable is already assigned.

The front end (DDC, Dartpad, main branch) reports:

main.dart:4:8: Error: Can't assign to the final variable 'c'.
  for (c in ints) {
       ^

The analysis should not consider c definitely assigned in the loop header (since it isn't definitely assigned, the example code above would only assign to it once).

The error message suggests that the logic for for/in (which is not well specified to begin with) has some clause saying that the variable must not be final. That would predate late variables, and shouldn't be take verbatim any more.
The variable must be assignable, which means it must:

  • not be const,
  • must not be final unless:
    • it's definitely unassgned, or
    • it's late and potentially unassigned.

Assignment analysis of a for/in (and while) loop should treat the loop variable as:

  • Definitely assigned if it's definitely assigned before the loop.
  • Potentially assigned before the loop assignment if it's not definitely assigned before the loop.
  • Definitely assigned after the loop assignment and after the loop.

Basically, it should work just as if the loop was written as:

void main() {
  late final int c;
  var ints = <int>[1];
  for (final int _$tmp in ints) { // Introduce same context type that `c` would.
    c = _$tmp;
    print(c);
  }
}

which both CFE and analyzer accepts.

(I don't think a late final loop variable is something anyone would ever write, so not a high priority to fix.)

@stereotype441

@lrhn lrhn added the area-dart-model For issues related to conformance to the language spec in the parser, compilers or the CLI analyzer. label Mar 19, 2025
@eernstg
Copy link
Member

eernstg commented Mar 19, 2025

The specification isn't entirely complete on this topic, but I do think we can find most of the rules that are needed to clarify this situation.

The for-in loop for (c in ints) ... is actually specified to perform an assignment to c during the execution of the body of the loop (quote from here):

If S is a for statement or a for element in a collection, whose forLoopParts take the form of a for-in loop, [then assignedIn(S) uses] the body of S [as its scope].
...
a loop of the form for (x in ...) ... (where x is declared elsewhere in the function) is considered to assign to x.

The rule about the flow analysis of a for-in statement is found later in the same document, but it doesn't spell out exactly how the assignment mentioned above is taken into account. There's a TODO about it:

this glosses over how we handle the implicit assignment to X.

This means that we can't see precisely how the for-in statement updates the variable model of c to represent the synthetic assignment to c in the body, but it seems reasonable to say that c is 'definitely assigned' in the body, after the synthetic assignment to c (if the flow analysis takes this assignment into account). It is also 'not definitely unassigned' in the body, and it is 'not definitely unassigned' in code which is executed after the body, and before the first iteration, and after the loop as a whole.

In particular, it would then be 'not definitely unassigned' before the synthetic assignment, which would imply that the synthetic assignment to c should not be reported as an error.

@johnniwinther johnniwinther added the model-flow Implementation of flow analysis in analyzer/cfe label Mar 19, 2025
@stereotype441
Copy link
Member

@lrhn

Assignment analysis of a for/in (and while) loop should treat the loop variable as:

  • Definitely assigned if it's definitely assigned before the loop.
  • Potentially assigned before the loop assignment if it's not definitely assigned before the loop.
  • Definitely assigned after the loop assignment and after the loop.

It's not sound to consider the loop variable as definitely assigned after the loop, because the loop might execute zero times. I think the last bullet should be replaced with something like:

  • Definitely assigned in the body of the loop (i.e. after the implicit assignment).
  • Potentially assigned after the loop.

(I don't think a late final loop variable is something anyone would ever write, so not a high priority to fix.)

Agreed. Accordingly, I'm classifying this as P3.

@stereotype441 stereotype441 added the P3 A lower priority bug or feature request label Mar 20, 2025
copybara-service bot pushed a commit that referenced this issue Mar 20, 2025
…igned_test.dart`.

Some of the tests in `assignment_to_final_local_test.dart` were
actually testing `late final` locals, so they make more sense in
`late_final_local_already_assigned_test.dart`.

This paves the way for fixing
#60359 (Using a `late final`
variable as loop variable for `for`/`in` gives incorrect late errors).

Change-Id: I58da6ae6791adb1b124129b30b0d8c62bfa2d519
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417000
Auto-Submit: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-dart-model For issues related to conformance to the language spec in the parser, compilers or the CLI analyzer. model-flow Implementation of flow analysis in analyzer/cfe P3 A lower priority bug or feature request
Projects
None yet
Development

No branches or pull requests

4 participants