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

Promote associated variables when passing a tuple to a switch #3163

Open
rrousselGit opened this issue Jun 23, 2023 · 3 comments
Open

Promote associated variables when passing a tuple to a switch #3163

rrousselGit opened this issue Jun 23, 2023 · 3 comments
Labels
feature Proposed language feature that solves one or more problems flow-analysis Discussions about possible future improvements to flow analysis type-inference Type inference, issues or improvements

Comments

@rrousselGit
Copy link

Consider the following code:

Object a;
Object b;
switch ((a, b)) {
  case (int(), int()):
    print('both are integers'); 
    a.isEven; // KO, a is still considered as Object
}

It would be neat if the compiler detected that we were doing a pattern on a/b and promoted them accordingly.

This would be equivalent to:

Object a;
switch (a) {
  case int():
    a.isEven; // works
}
@rrousselGit rrousselGit added the feature Proposed language feature that solves one or more problems label Jun 23, 2023
@rrousselGit
Copy link
Author

rrousselGit commented Jun 23, 2023

Currently the workaround is to shadow the variables:

Object a;
Object b;
switch ((a, b)) {
  case (final int a, final int b): // declare new variables
    print('both are integers'); 
    a.isEven; // works
}

But that sounds a bit redundant.

Outside of verbosity, this is quite error-prone too. It could be easily to incorrectly swap the names:

switch ((a, b)) {
  case (final int b, final int a): // oopsy
}

@lrhn
Copy link
Member

lrhn commented Jun 23, 2023

This is variable/value aliasing.

To be able to promote the a variable in the first example, we need to know that the value in position $1 of the record value being switched on, is an alias for the value of a.

We have something similar for the outer value of a switch:

Object a = 1;
switch (a) {
  case int():  print(a.isEven);
}

This works because we know the value being switched on is the same value as the variable a, so promoting that value also promotes a. The value exists independently of the variable, and the link can be broken by assigning to a:

Object a = 1;
switch (a) {
  case String():  print(a.substring(0)); // Valid!
  case bool() when a = false: print("nope"); // Break link to variable.
  case int(): print(a.isEven); // ERROR.
}

Here the third case becomes an error, because while we're checking the same value in all the cases,
it only aliases a until we (might) assign to a. After that, it's just a value.

If we can, somehow, keep the same kind of link between fields of a record (which is known to b immutable, that makes everything much simpler), we could allow checks against the record field to affect promotion of the aliased variable, as long as we believe it's still aliasing that variable.

So, not completely impossible, but does require keeping more information around, tracking it, and invalidating it correctly.

And also, should it only affect switch cases, or should it work in general?

Object a = 1;
var pair = (a, 42);
if (pair.$1 is int) print(a.isEven); // Valid?

That might get complicated fast. Or maybe it's trivial, what do I know 😉.

(If we generally keep aliasing information for all the values, we could also update it on assignments.

Object o1 = 1;
Object o2 = "String";
if (o1 is int) print(o1.isEven);
o1 = o2; // value of o1 now aliases both o1 and o2
if (o1 is String) { // Promotes both `o1` and `o2`, because we know it's the same value.
  o1 = 42;
  print(o2.substring(0));
}

This could get even more complicated. But if we can track promotions through boolean variables,
this doesn't sound that far-fetched. @stereotype441)

@rrousselGit
Copy link
Author

I believe "switch" is the main use-case. I'm not sure we'd want this for ifs.
In fact, IMO this should only apply to records that are directly constructor in the switch case.

So:

var a = 42;
var b= 21;
switch ((a, b)) {
...
}

But not:

var a = 42;
var b= 21;
final record = (a, b);
switch (record) {
...
}

Basically, this is about making a switch case on multiple values at once.

The idea is quite similar to #3160, and the pattern seems to be official (#2563 (comment))

@lrhn lrhn added the type-inference Type inference, issues or improvements label Jun 26, 2023
@stereotype441 stereotype441 added the flow-analysis Discussions about possible future improvements to flow analysis label Jul 26, 2024
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 type-inference Type inference, issues or improvements
Projects
None yet
Development

No branches or pull requests

3 participants