Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't instanceof pattern matching work with else if in this particular case?

The following snippet does not compile on javac, version 17 (Temurin)

class Instanceof {
    static void doesNotWork(Object o) {
        if (o == null) {
            throw new Error();
        } else if (!(o instanceof String s)) {
            throw new Error();
        }   
        System.out.println(s); // error here
    }
}

It generates this error: cannot find symbol

cannot find symbol
symbol:   variable s
location: class Instanceof

However, the following (in my opinion) equivalent variations work: With an explicit else block:

static void doesWork(Object o) {
    if (o == null) {
        throw new Error();
    } else if (!(o instanceof String s)) {
        throw new Error();
    } else {
        System.out.println(s);
    }
}

Or without an else:

static void doesWork(Object o) {
    if (o == null) {
        throw new Error();
    }
    if (!(o instanceof String s)) {
        throw new Error();
    }
    System.out.println(s);
}

Or with a single if:

static void doesWork(Object o) {
    if (o == null || !(o instanceof String s)) {
        throw new Error();
    }
    System.out.println(s);
}

Is this a bug in javac? If yes, should I report this, but where exactly?

like image 599
Fabian Kürten Avatar asked Sep 06 '25 07:09

Fabian Kürten


2 Answers

The doesNotWork case is equivalent to this:

static void doesNotWork(Object o) {
    if (o == null) {
        throw new Error();
    } else {
        if (!(o instanceof String s)) {
            throw new Error();
        }
    }
    System.out.println(s); // error here
}

This makes it more obvious that String s is inside a block bounded by curly brackets and is therefore out of scope in the same way that this doesn't work either:

static void doesNotWork(Object o) {
    {
        if (!(o instanceof String s)) {
            throw new Error();
        }
    }
    System.out.println(s); // error here
}

In the case where it does work, with the println inside the else, it's equivalent to this:

if (o == null) {
    throw new Error();
} else {
    if (!(o instanceof String s)) {
        throw new Error();
    } else {
        System.out.println(s);
    }
}

Which shows the println being in scope.

like image 195
k314159 Avatar answered Sep 08 '25 21:09

k314159


The relevant bug ticket has been created in the OpenJdk Jira. It is marked as reproduceable so most probably will be handled as bug, and fixed.

Here is the aforementioned ticket so we can trace the progress.

Edit: Seems that this issue is going to affect JDK 20 as well. Resolution is going to take some time.

like image 34
Panagiotis Bougioukos Avatar answered Sep 08 '25 19:09

Panagiotis Bougioukos