ADDITIONAL SYSTEM INFORMATION :
OS: Microsoft Windows 10 Pro 10.0.19045 build 19045
Java version: OpenJDK 20.0.2 (Downloaded through Intellij Idea 2023.2)
A DESCRIPTION OF THE PROBLEM :
See source code below. The code compiles successfully, however running it gives `VerifyError`. The error disappears when:
- either branch is removed
- when using different variables:
```
// fine
-> throw new UnsupportedOperationException("some error");
-> throw new UnsupportedOperationException("another error");
// fine
-> throw new UnsupportedOperationException(e.toString());
-> throw new UnsupportedOperationException(e.toString());
// fine
-> throw new UnsupportedOperationException(v.toString());
-> throw new UnsupportedOperationException(e.toString());
// not fine
-> throw new UnsupportedOperationException(e.toString());
-> throw new UnsupportedOperationException(v.toString());
// not fine
-> throw new UnsupportedOperationException(v.toString());
-> throw new UnsupportedOperationException(v.toString());
```
The error persists even if:
- the branches use different variable names (`v1`, `v2`, `e1` and `e2` for example)
- guards are used (`v.value() == 1` for example)
- `var` is replaced with the actual type
REGRESSION : Last worked in version 19
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile with: `javac --enable-preview --source 20 ./Test.java`
Run with: `java --enable-preview --source 20 Test`
Or with just the `java` tool: `java --enable-preview --source 20 Test.java`
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Code runs without errors
ACTUAL -
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:
Location:
random/Test.eval(Lrandom/Test$Expr;)I @178: aload
Reason:
Type top (current frame, locals[7]) is not assignable to reference type
Current Frame:
bci: @178
flags: { }
locals: { 'random/Test$Expr', 'random/Test$Expr', integer, 'random/Test$Plus', top, top, 'random/Test$Expr', top, 'random/Test$Expr', integer }
stack: { uninitialized 174, uninitialized 174 }
Bytecode:
0000000: 2a59 b800 1757 4c03 3d2b 1cba 001d 0000
0000010: ab00 0000 0000 00b0 0000 0001 0000 0000
0000020: 0000 0014 2bc0 0007 4e2d b600 213a 0803
0000030: 3609 1908 1509 ba00 2500 00aa 0000 0080
0000040: ffff ffff 0000 0001 0000 0046 0000 0019
0000050: 0000 0046 1908 c000 093a 042d b600 263a
0000060: 0a19 0a3a 0519 04b6 0029 049f 0009 0436
0000070: 09a7 ffc1 bb00 2d59 1904 b600 2fb7 0033
0000080: bf19 083a 0619 06c6 0027 2db6 0026 3a0a
0000090: 190a c100 0999 0013 190a c000 093a 0719
00000a0: 07b6 0029 049f 0009 0536 09a7 ff87 bb00
00000b0: 2d59 1907 b600 2fb7 0033 bf04 3da7 ff4c
00000c0: 03a7 0003 ac4c bb00 3859 2bb6 003a 2bb7
00000d0: 003b bf
Exception Handler Table:
bci [42, 45] => handler: 197
bci [92, 95] => handler: 197
bci [139, 142] => handler: 197
Stackmap Table:
append_frame(@9,Object[#67],Integer)
same_frame(@36)
full_frame(@50,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
same_frame(@84)
full_frame(@116,{Object[#67],Object[#67],Integer,Object[#7],Object[#9],Object[#67],Top,Top,Object[#67],Integer},{})
full_frame(@129,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
full_frame(@168,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Object[#67],Top,Object[#67],Integer},{})
same_frame(@174)
full_frame(@187,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
full_frame(@192,{Object[#67],Object[#67],Integer},{})
full_frame(@196,{Object[#67]},{Integer})
same_locals_1_stack_item_frame(@197,Object[#54])
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:496)
at java.base/java.lang.Class.forName(Class.java:475)
at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:425)
at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:205)
at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
---------- BEGIN SOURCE ----------
public class Test {
public static void main(String[] args) {
eval(new Plus(new Value(1), new Value(2)));
}
private static int eval(Expr expr) {
return switch (expr) {
case Plus(Value v, var e) -> throw new UnsupportedOperationException(v.toString());
case Plus(var e, Value v) -> throw new UnsupportedOperationException(v.toString());
default -> 0;
};
}
private sealed interface Expr permits Value, Plus {}
private record Value(int value) implements Expr {}
private record Plus(Expr left, Expr right) implements Expr {}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Using if-else chain with `instanceof` works as expected
FREQUENCY : always
OS: Microsoft Windows 10 Pro 10.0.19045 build 19045
Java version: OpenJDK 20.0.2 (Downloaded through Intellij Idea 2023.2)
A DESCRIPTION OF THE PROBLEM :
See source code below. The code compiles successfully, however running it gives `VerifyError`. The error disappears when:
- either branch is removed
- when using different variables:
```
// fine
-> throw new UnsupportedOperationException("some error");
-> throw new UnsupportedOperationException("another error");
// fine
-> throw new UnsupportedOperationException(e.toString());
-> throw new UnsupportedOperationException(e.toString());
// fine
-> throw new UnsupportedOperationException(v.toString());
-> throw new UnsupportedOperationException(e.toString());
// not fine
-> throw new UnsupportedOperationException(e.toString());
-> throw new UnsupportedOperationException(v.toString());
// not fine
-> throw new UnsupportedOperationException(v.toString());
-> throw new UnsupportedOperationException(v.toString());
```
The error persists even if:
- the branches use different variable names (`v1`, `v2`, `e1` and `e2` for example)
- guards are used (`v.value() == 1` for example)
- `var` is replaced with the actual type
REGRESSION : Last worked in version 19
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile with: `javac --enable-preview --source 20 ./Test.java`
Run with: `java --enable-preview --source 20 Test`
Or with just the `java` tool: `java --enable-preview --source 20 Test.java`
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Code runs without errors
ACTUAL -
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:
Location:
random/Test.eval(Lrandom/Test$Expr;)I @178: aload
Reason:
Type top (current frame, locals[7]) is not assignable to reference type
Current Frame:
bci: @178
flags: { }
locals: { 'random/Test$Expr', 'random/Test$Expr', integer, 'random/Test$Plus', top, top, 'random/Test$Expr', top, 'random/Test$Expr', integer }
stack: { uninitialized 174, uninitialized 174 }
Bytecode:
0000000: 2a59 b800 1757 4c03 3d2b 1cba 001d 0000
0000010: ab00 0000 0000 00b0 0000 0001 0000 0000
0000020: 0000 0014 2bc0 0007 4e2d b600 213a 0803
0000030: 3609 1908 1509 ba00 2500 00aa 0000 0080
0000040: ffff ffff 0000 0001 0000 0046 0000 0019
0000050: 0000 0046 1908 c000 093a 042d b600 263a
0000060: 0a19 0a3a 0519 04b6 0029 049f 0009 0436
0000070: 09a7 ffc1 bb00 2d59 1904 b600 2fb7 0033
0000080: bf19 083a 0619 06c6 0027 2db6 0026 3a0a
0000090: 190a c100 0999 0013 190a c000 093a 0719
00000a0: 07b6 0029 049f 0009 0536 09a7 ff87 bb00
00000b0: 2d59 1907 b600 2fb7 0033 bf04 3da7 ff4c
00000c0: 03a7 0003 ac4c bb00 3859 2bb6 003a 2bb7
00000d0: 003b bf
Exception Handler Table:
bci [42, 45] => handler: 197
bci [92, 95] => handler: 197
bci [139, 142] => handler: 197
Stackmap Table:
append_frame(@9,Object[#67],Integer)
same_frame(@36)
full_frame(@50,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
same_frame(@84)
full_frame(@116,{Object[#67],Object[#67],Integer,Object[#7],Object[#9],Object[#67],Top,Top,Object[#67],Integer},{})
full_frame(@129,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
full_frame(@168,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Object[#67],Top,Object[#67],Integer},{})
same_frame(@174)
full_frame(@187,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
full_frame(@192,{Object[#67],Object[#67],Integer},{})
full_frame(@196,{Object[#67]},{Integer})
same_locals_1_stack_item_frame(@197,Object[#54])
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:496)
at java.base/java.lang.Class.forName(Class.java:475)
at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:425)
at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:205)
at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
---------- BEGIN SOURCE ----------
public class Test {
public static void main(String[] args) {
eval(new Plus(new Value(1), new Value(2)));
}
private static int eval(Expr expr) {
return switch (expr) {
case Plus(Value v, var e) -> throw new UnsupportedOperationException(v.toString());
case Plus(var e, Value v) -> throw new UnsupportedOperationException(v.toString());
default -> 0;
};
}
private sealed interface Expr permits Value, Plus {}
private record Value(int value) implements Expr {}
private record Plus(Expr left, Expr right) implements Expr {}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Using if-else chain with `instanceof` works as expected
FREQUENCY : always