vrchat-community / UdonSharp

A compiler for compiling C# to Udon assembly
https://udonsharp.docs.vrchat.com
MIT License
463 stars 50 forks source link

switch case default evaluation incorrect in 1.0.0b12 #26

Closed mahuvrc closed 2 years ago

mahuvrc commented 2 years ago

After updating to 1.0.0b12 from 0.20.3 on one of my old projects I found an issue with switch case statement evaluation order. Hopefully this is the right repo for the U# 1.0 beta

The default: case is being evaluated and short circuited when it's the first case. Meaning any case after the default case is effectively ignored. From what I can tell, this is only happening when it's the first case and when there are no other case labels on the case.

Conventionally in almost every switch statement I put the default case last, but in some of my code I put the default case first when it makes sense to order them as such and getting different behavior all of a sudden after updating was really sneaky!

Here's a simple demo script:

using UdonSharp;
using UnityEngine;

public class SwitchDefaultTest : UdonSharpBehaviour
{
    private int counter = 0;
    public override void Interact()
    {
        counter++;
        switch (counter % 3)
        {
            default:
                Debug.Log($"Default case - counter = {counter}");
                break;
            case 1:
                Debug.Log($"case 1 - counter = {counter}");
                    break;
            case 2:
                Debug.Log($"case 2 - counter = {counter}");
                break;
        }
    }

In 0.20.3 pressing the button repeatedly leads to all 3 cases being executed and logged appropriately.

2022.04.16 17:32:23 Log        -  case 1 - counter = 1
2022.04.16 17:32:24 Log        -  case 2 - counter = 2
2022.04.16 17:32:25 Log        -  Default case - counter = 3
2022.04.16 17:32:27 Log        -  case 1 - counter = 4
2022.04.16 17:32:28 Log        -  case 2 - counter = 5
2022.04.16 17:32:29 Log        -  Default case - counter = 6
2022.04.16 17:32:30 Log        -  case 1 - counter = 7
... etc

In 1.0.0b12 pressing the button always leads to the default case being executed and logged.

2022.04.16 17:39:03 Log        -  Default case - counter = 1
2022.04.16 17:39:03 Log        -  Default case - counter = 2
2022.04.16 17:39:04 Log        -  Default case - counter = 3
2022.04.16 17:39:04 Log        -  Default case - counter = 4
2022.04.16 17:39:04 Log        -  Default case - counter = 5
2022.04.16 17:39:05 Log        -  Default case - counter = 6
2022.04.16 17:39:05 Log        -  Default case - counter = 7

(An interesting thing I noticed was that adding a dummy case label to the demo script as follows it changes the behavior back to the expected default case behavior)

...
            default:
            case 9999999: // this added label can never be reached, but the default case now acts appropriately
                Debug.Log($"Default case - counter = {counter}");
                break;
...