Interesting switch pattern-matching snippets that don't compile but maybe should

Robbe Pincket robbepincket at live.be
Sun Jan 22 00:27:27 UTC 2023


Hi folks

While writing a snippet to show how cool switch pattern matching is,
I managed to conceive some of *interesting* snippets, some of which
fail to compile with the openjdk early access build 32, but I don't
see why they aren't considered valid according to the spec.

Let's start with a normal working snippet

```
sealed interface Uber<T> permits Base, Relieve {}
sealed interface Base<T> extends Uber<T> permits Foo, Bar, Other{}
record Foo() implements Base<String>{}
record Bar() implements Base<Long>{}
record Other<T>() implements Uber<T>{}
record Relieve() implements Uber<Integer> {}

class Test {
    static Uber<Integer> foo() {
        return null;
    }

    static Base<Integer> bar() {
        return null;
    }

    static String test1a(){
        return switch (bar()){
            case null -> "Hi";
            case Other<Integer> o -> "Hello";
        };
    }

    static String test1b(){
        return switch (foo()){
            case null -> "Hi";
            case Relieve r -> "Hey";
            case Other<Integer> o -> "Hello";
        };
    }

    static String test2(){
        return switch (bar()){
            case Other<Integer> o -> "Hello";
        };
    }

    static String test3(){
        switch (bar()){
            case Other<Integer> o -> {
                return "Hello";
            }
        }
    }
}
```

This compiles perfectly fine, however,
things change when we remove the `other` class.

```
sealed interface Uber<T> permits Base, Relieve {}
sealed interface Base<T> extends Uber<T> permits Foo, Bar{}
record Foo() implements Base<String>{}
record Bar() implements Base<Long>{}
record Relieve() implements Uber<Integer> {}
```

Let's look at each method individually

```
static String test1a(){
    return switch (bar()){
        case null -> "Hi";
    };
}
```

This fails with the following error:

> the switch expression does not cover all possible input values

This might seem obvious to some, given that there is no case
for `Base<Integer>`, but note `test1b`:

```
static String test1b(){
    return switch (foo()){
        case null -> "Hi";
        case Relieve r -> "Hey";
    };
}
```

This compiles perfectly fine, even though there is no case that
covers `Base<Integer>` or part of it.

As far as I can see, the spec does not give any reason as to why
this version of `test1a` shouldn't compile, and disagrees with
the reason given by javac.

Now for test2.

```
static String test2(){
    return switch (bar()){};
}
```

This is against the spec:

> It is a compile-time error if a switch expression has no result expressions.

test3:
```
static String test3(){
    switch (bar()){};
}
```

This one, after a bit more checking is also, illegal according
to the spec, but we aren't in the clear yet. The only reason I
could find that `test3` was illegal is "14.22. Unreachable Statements".

> A switch statement whose switch block is empty [...] can complete normally.

This means our methodblock can complete normally which isn't allowed.
Note that javac complains again about the switch not covering
all input values, which isn't true.

We can fix our method however, so it is valid according to the spec.


```
static String test3(){
    String s;
    switch (bar()){};
    return s;
}
```

Now this might seems crazy, but Chapter 16. Definite Assignment
sees the switch differently, and "realizes" that the switch
can not complete normally, (read: all variables are considered
to be both definite unassigned and definite assigned). As a
result we can read from `s` even though there are no assignments.

This does not work however, and just adds a second error:

> variable s might not have been initialized

Greetings
Robbe Pincket
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230122/9e9441b7/attachment-0001.htm>


More information about the amber-dev mailing list