JDK 17: Switch statement causes java.lang.VerifyError: Bad type on operand stack
Asked Answered
L

2

5

Just tried JDK17 on Eclipse 2021-09 to have it fail with a java.lang.VerifyError, which wasn't very helpful itself. I tracked it down to a switch statement, that gets fed a value pulled out of a Map or another generic type. If I use a local variable in the switch statement instead, everything works as intended.

Test code:

import java.util.HashMap;
import java.util.Map;

public class SwitchFail {
  public static void main(String[] args) {
    //doesnt work
    Map<Integer, String> stringMap = new HashMap<>();
    stringMap.put(1, "Test");
    switch(stringMap.get(1)) {
    }

    //works
    String plainString = "Test";
     switch(plainString) {
    }
  }
}

This throws the following error:

Error: Unable to initialize main class SwitchFail
Caused by: java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    SwitchFail.main([Ljava/lang/String;)V @33: invokevirtual
  Reason:
    Type 'java/lang/Object' (current frame, stack[0]) is not assignable to 'java/lang/String'
  Current Frame:
    bci: @33
    flags: { }
    locals: { '[Ljava/lang/String;', 'java/util/HashMap', 'java/lang/Object' }
    stack: { 'java/lang/Object' }
  Bytecode:
    0000000: bb00 1059 b700 124c 2b04 b800 1312 19b9
    0000010: 001b 0300 572b 04b8 0013 b900 2102 0059
    0000020: 4db6 0025 57b1  

                   
            

Didn't try another JDK between 11 and 17 yet. Switches gained some new functions between those versions, so that might be it. Maybe it's a problem in the Eclipse JDT or my local JDK, so any tries to reproduce this error on another configuration or IDE would be great. Tried on OpenJDK (build 17+35-2724) for macOS.

Edit: Also happens on

List<String> stringList = Arrays.asList("Test");
switch(stringList.get(0)) {}

Most likely an issue with the new JDT for Java 17 or my local installation.

Lorenelorens answered 15/9, 2021 at 16:50 Comment(9)
How about the case where you get the string from the map, assign it to a temporary variable. and switch on the temporary?Plumbing
Using Eclipse Version: 2020-09 (4.17.0) Build id: 20200910-1200 your code works.Radley
@Radley - I am inclined to suspect a compiler problem, and I think your experience might support that.Plumbing
@Plumbing Saving it to a local var first works. This looks like some type of type inference issue. Trying on a windows machine or the Oracle JDK next.Lorenelorens
What's the question?Taut
I'm going to go so far as to say what I think the compiler bug is: ecj is failing to insert the implicit cast that results from calling get with a map of a generic type because it doesn't look into the switch body to realize that the narrowed type is required.Ailsa
@chrylis-cautiouslyoptimistic- Yes, it has to do with generic type inference as it also happens with List<String> stringList = Arrays.asList("Test"); switch(stringList.get(0)) {}. It's probably rooted in the JDT or my local installation.Lorenelorens
Eclipse 2021-09 does not support Java 17. You have installed the preview of Java 17 support that will be released in December. Please report this issue to Eclipse here: bugs.eclipse.org/bugs/enter_bug.cgi?product=JDTTranspire
@Transpire Just filed a bug there. Thanks for the hint. I wanted to get some feedback first.Lorenelorens
L
3

This was indeed a bug in Eclipse's JDT. I can confirm this was fixed after Bug 576093 was closed. There is an update available.

Lorenelorens answered 26/10, 2021 at 8:9 Comment(0)
F
3

It is a problem with your Eclipse, not with Java-17 itself. Java-17 has been released only yesterday. Wait for some time until the IDEs are updated to support Java-17.

Demo:

import java.util.HashMap;
import java.util.Map;

public class SwitchFail {
    public static void main(String[] args) {
        Map<Integer, String> stringMap = new HashMap<>();
        stringMap.put(1, "Test");
        switch (stringMap.get(1)) {
        default:
            System.out.println("Hello");
        }

        String plainString = "Test";
        switch (plainString) {
        default:
            System.out.println("Hi");
        }
    }
}

A sample run:

[~/Desktop]: java SwitchFail.java
Hello
Hi

Test with jar:

[~/Desktop/java17]: javac SwitchFail.java 
[~/Desktop/java17]: jar -cvf java17test.jar .
added manifest
adding: SwitchFail.java(in = 379) (out= 212)(deflated 44%)
adding: SwitchFail.class(in = 920) (out= 546)(deflated 40%)
adding: .DS_Store(in = 6148) (out= 178)(deflated 97%)
[~/Desktop/java17]: java -cp java17test.jar SwitchFail
Hello
Hi

The JDK on my system:

[~/Desktop/java17]: java -version
openjdk version "17" 2021-09-14
OpenJDK Runtime Environment (build 17+35-2724)
OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode, sharing)
Furan answered 15/9, 2021 at 17:10 Comment(6)
Also getting the same result when executing that via java -jar directly. Although still compiled and exported to jar via eclipse.Lorenelorens
@Lorenelorens - That's what I have mentioned that it's a problem with your Eclipse, not with Java-17 itself. Create jar without using Eclipse.Furan
@Lorenelorens - I have added an update for jar as well. Feel free to comment in case of any doubt or issue.Furan
Thank you for your help and feedback. When I compile the class using javac, everything works as intended. I guess it's a bug in the JDT or my local installation is broken.Lorenelorens
@Lorenelorens The worst thing you can do is "Wait for some time" instead of making sure it has been reported to Eclipse. Please note, you have probably installed the current preview of Java 17 support that will be released on December 15, 2021.Transpire
@Transpire You've already seen this, but this bug is reported under bugs.eclipse.org/bugs/show_bug.cgi?id=576008Lorenelorens
L
3

This was indeed a bug in Eclipse's JDT. I can confirm this was fixed after Bug 576093 was closed. There is an update available.

Lorenelorens answered 26/10, 2021 at 8:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.