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

Code after switch statements consider variable not initialized, but using a switch expression works #4272

Open
rrousselGit opened this issue Feb 22, 2025 · 5 comments
Labels
request Requests to resolve a particular developer problem

Comments

@rrousselGit
Copy link

Consider those two switches:

final value = switch ([]) {
  [] => 'a',
  [final first] => 'b',
  [_, ...] => 'c',
};
print(value.length);
final String value;
switch ([]) {
  case []:
    value = 'a';
  case [final first]:
    value = 'b';
  case [_, ...]:
    value = 'c';
}
print(value.length);

Both switch have the exact same cases. but in the second case, value is considered not initialized, with the following error:

The final variable 'value' can't be read because it's potentially unassigned at this point.
Ensure that it is assigned on necessary execution paths.

My guess is that this is related to Collection pattern match. But considering one switch works, could we make other kinds of switch work too?

@rrousselGit rrousselGit added the request Requests to resolve a particular developer problem label Feb 22, 2025
@lrhn
Copy link
Member

lrhn commented Feb 22, 2025

Sounds like a difference between inference guessing at exhaustiveness and the exhaustiveness checking algorithm doing better.

The first example is a switch expression. It must be exhaustive, so the inference algorithm just assumes that it is, and lets the exhaustiveness checking algorithm check it, which is successful.

The second example is a switch statement which is allowed to not be exhaustive. The inference algorithm does a best-effort check to see if it looks exhaustive. It fails, so it assumes the switch is not exhaustive.
Since it doesn't have to be exhaustive, the exhaustiveness checking algorithm is never run.

@stereotype441

@mateusfccp
Copy link
Contributor

mateusfccp commented Feb 22, 2025

My guess is that it is (simply?) not considered in flow analysis. The cases are clearly exhaustive, or else you would have a different error, and it would be emitted in both cases.

I can't test now, but do statement switches ever be considered in flow analysis? For instance, if we were dealing with a boolean or an enum instead of a list.

@rrousselGit
Copy link
Author

rrousselGit commented Feb 22, 2025

Sealed patterns work:

sealed class Foo {}
class Bar extends Foo {}
class Baz extends Foo {}

void main() {
    Foo value = Bar();
    final String result;
    switch (value) {
      case Bar():
        result = 'bar';
      case Baz():
        result = 'baz';
    }

    print(result.length); // OK
}

Other random patterns work too:

int value = 42;
final String result;
switch (value) {
  case 42:
    result = 'bar';
  case _:
    result = 'baz';
}

print(result.length); // Valid too

Same with bools/enums.

The issue seems to be with collections.

@rrousselGit
Copy link
Author

Some simpler List patterns work too:

List<String> value = [];
final String result;
switch (value) {
  case ['foo']:
    result = 'bar';
  case [...]:
    result = 'baz';
}

So something with the OP's example uniquely breaks this.

@stereotype441
Copy link
Member

See also #2977

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

4 participants