sdk icon indicating copy to clipboard operation
sdk copied to clipboard

Join if statements with if case and boolean should add `when` or continue it

Open FMorschel opened this issue 1 year ago • 9 comments
trafficstars

If you have the following code, in both inner if there is a Join if statement but when it does so, the case statements are broken.

if (x case int v) {
  if (x == 0) ;
}
if (x case int()) {
  if (x == 0) ;
}

I'd expect either this to know the value for the outer if (since it knows it is there) or to revert the changes if it detects this happens.

FMorschel avatar Sep 12 '24 05:09 FMorschel

Summary: The issue reports that the "Join if statement" refactoring breaks case statements within nested if statements. The user expects the refactoring to either correctly handle the nested case statements or revert the changes to avoid breaking the code.

dart-github-bot avatar Sep 12 '24 05:09 dart-github-bot

After some more thinking.

The current output if we join the first two:

if (x && x == 0) {
}

It would be fine if the output was:

if (x case int v when x == 0) {
}

FMorschel avatar Oct 17 '24 11:10 FMorschel

A little more testing. If the first one already had a case, it removes it completely today.

if (x case int v when true) {
  if (x == 0) ;
}

Becomes:

if (x && x == 0) {
;    /// <--- should also remove this since it is useless (only happens when the inner `if` ends in `;`)
}

FMorschel avatar Oct 17 '24 12:10 FMorschel

I finished implementation of this, will add PR soon. :)

tenhobi avatar Oct 19 '24 08:10 tenhobi

I think it is safe to convert

if (e case p when b) {
  if (b2) stmt
}

into

if (e case p when b && b2) stmt

(and if the original had no when clause, then just ... when b2).

If the inner if is also a case condition, that won't work, sadly.

Other than that it should follow the same rules for when it applies as combining two plain if conditions with &&.

(So: if inner is case expression, you cannot combine. If outer is, you combine into when clause. I don't see any extra complications.)

lrhn avatar Oct 19 '24 09:10 lrhn

@lrhn i have it working when inner is not if-case. It's a good point that I should also check whether the inner is if-case and if so, don't assist. I will add test for this too. 👍 Btw. I think we can also merge if outer is normal if and inner is if-case, right?

if (a) {
  if (b case c when d) {} 
}

into

if (b case c when a && d) {}

tenhobi avatar Oct 19 '24 09:10 tenhobi

I think we can also merge if outer is normal if and inner is if-case, right?

Not in general. It changes the evaluation order. If the inner expression depends on promotion from the outer test, that test can't be moved to after the pattern.

lrhn avatar Oct 19 '24 09:10 lrhn

You are right, I will update the implementation according to what you say. :)

tenhobi avatar Oct 19 '24 10:10 tenhobi

One more thing I realised. @lrhn please say so if this should be a separate issue.

Could we add the option to join inner if with else:

if (a) {
} else {
  if (b) {
  } else if (c) {
  }
}

Could become:

if (a) {
} else if (b) {
} else if (c) {
}

Not sure if it makes sense for the current message we have for the assist, but anyway.

FMorschel avatar Oct 20 '24 02:10 FMorschel

I would make that a different assist with a different message.

bwilkerson avatar Oct 20 '24 04:10 bwilkerson

This have been merged in https://dart-review.googlesource.com/c/sdk/+/390632, can you @FMorschel please close this issue? :)

tenhobi avatar Oct 21 '24 19:10 tenhobi