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

Emit switch bytecode when matching unions of a switchable type #20410

Closed
dwickern opened this issue May 15, 2024 · 0 comments · Fixed by #20411
Closed

Emit switch bytecode when matching unions of a switchable type #20410

dwickern opened this issue May 15, 2024 · 0 comments · Fixed by #20411
Labels
itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label

Comments

@dwickern
Copy link
Contributor

dwickern commented May 15, 2024

Scala emits a switch instruction when matching on Int or String but not when matching on a union of those types.

Compiler version

3.3.3, 3.4.1

Minimized code

def matchInt(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case 4 => "four"
  case 5 => "five"
}

def matchIntUnion(x: 1 | 2 | 3 | 4 | 5): String = x match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case 4 => "four"
  case 5 => "five"
}

def matchString(s: String): Int = s match {
  case "one"   => 1
  case "two"   => 2
  case "three" => 3
  case "four"  => 4
  case "five"  => 5
}

def matchStringUnion(s: "one" | "two" | "three" | "four" | "five"): Int = s match {
  case "one"   => 1
  case "two"   => 2
  case "three" => 3
  case "four"  => 4
  case "five"  => 5
}

Output

The above code (de)compiles to:

public String matchInt(final int x) {
    switch (x) {
        case 1:
            return "one";
        case 2:
            return "two";
        case 3:
            return "three";
        case 4:
            return "four";
        case 5:
            return "five";
        default:
            throw new MatchError(BoxesRunTime.boxToInteger(x));
    }
}

public String matchIntUnion(final int x) {
    if (1 == x) {
        return "one";
    } else if (2 == x) {
        return "two";
    } else if (3 == x) {
        return "three";
    } else if (4 == x) {
        return "four";
    } else if (5 == x) {
        return "five";
    } else {
        throw new MatchError(BoxesRunTime.boxToInteger(x));
    }
}

public int matchString(final String s) {
    switch (s == null ? 0 : s.hashCode()) {
        case 110182:
            if ("one".equals(s)) {
                return 1;
            }
            break;
        case 115276:
            if ("two".equals(s)) {
                return 2;
            }
            break;
        case 3143346:
            if ("five".equals(s)) {
                return 5;
            }
            break;
        case 3149094:
            if ("four".equals(s)) {
                return 4;
            }
            break;
        case 110339486:
            if ("three".equals(s)) {
                return 3;
            }
    }

    throw new MatchError(s);
}

public int matchStringUnion(final String s) {
    if ("one".equals(s)) {
        return 1;
    } else if ("two".equals(s)) {
        return 2;
    } else if ("three".equals(s)) {
        return 3;
    } else if ("four".equals(s)) {
        return 4;
    } else if ("five".equals(s)) {
        return 5;
    } else {
        throw new MatchError(s);
    }
}

Expectation

Emit a switch instruction when all members of the union share a base type with a switch-compatible type. For example:

  • matching on 1 | 2 | 3 | 4 | 5 can emit a switch because the union widens to Int
  • matching on "one" | "two" | "three" | "four" | "five" can emit a switch because the union widens to String
  • matching on 'a' | 'b' | 'c' can emit a switch because the union widens to Char
  • matching on 1 | 2 | 3 | "four" | "five" cannot emit a switch

Byte or Short can also be used in a switch but there's no syntax to make literals for those types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant