-
Bug
-
Resolution: Fixed
-
P3
-
19
-
b29
-
generic
-
generic
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8289242 | 20 | Jan Lahoda | P3 | Resolved | Fixed | b04 |
JDK-8291320 | 19.0.2 | Jan Lahoda | P3 | Resolved | Fixed | b01 |
JDK-8291148 | 19.0.1 | Jan Lahoda | P3 | Resolved | Fixed | b04 |
ADDITIONAL SYSTEM INFORMATION :
Ubuntu 20.04
OpenJDK Runtime Environment (build 19-ea+25-1892)
A DESCRIPTION OF THE PROBLEM :
A method that uses instanceof pattern matching for records fails with a verify error. Rewriting it with classic instanceof succeeds.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the program below with Java 19.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program runs and prints 3660.0 s
ACTUAL -
Error: Unable to initialize main class Test3
Caused by: java.lang.VerifyError: Bad return type
Exception Details:
Location:
Test3.$proxy$unit(LLength;)LLengthUnit; @4: areturn
Reason:
Type 'QuantityUnit' (current frame, stack[0]) is not assignable to 'LengthUnit' (from method signature)
Current Frame:
bci: @4
flags: { }
locals: { 'Length' }
stack: { 'QuantityUnit' }
Bytecode:
0000000: 2ab6 001a b04c bb00 0959 2bb6 000b 2bb7
0000010: 000f bf
Exception Handler Table:
bci [0, 4] => handler: 5
Stackmap Table:
same_locals_1_stack_item_frame(@5,Object[#7])
---------- BEGIN SOURCE ----------
interface QuantityUnit {
double factor();
}
enum LengthUnit implements QuantityUnit {
m(1), cm(0.01), in(0.01 / 2.54);
private final double factor;
public double factor() {
return factor;
}
LengthUnit(double factor) {
this.factor = factor;
}
public static final LengthUnit PREFERRED = m;
}
enum TimeUnit implements QuantityUnit {
s(1), min(60), h(60 * 60);
private final double factor;
public double factor() {
return factor;
}
TimeUnit(double factor) {
this.factor = factor;
}
public static final TimeUnit PREFERRED = s;
}
sealed interface Quantity {
double value();
QuantityUnit unit();
}
record Length(double value, LengthUnit unit) implements Quantity {
public String toString() {
return value() + " " + unit();
}
}
record Time(double value, TimeUnit unit) implements Quantity {
public String toString() {
return value() + " " + unit();
}
}
public class Test3 {
public static <T extends Quantity> T add1(T first, T second) {
if (first instanceof Time && second instanceof Time) {
var v1 = first.value();
var u1 = ((Time) first).unit();
var v2 = second.value();
var u2 = second.unit();
if (u1 == u2)
return (T) new Time(v1 + v2, u1);
else
return (T) new Time(v1 * u1.factor() + v2 * u2.factor(),
TimeUnit.PREFERRED);
}
else if (first instanceof Length && second instanceof Length) {
var v1 = first.value();
var u1 = ((Length) first).unit();
var v2 = second.value();
var u2 = second.unit();
if (u1 == u2)
return (T) new Length(v1 + v2, u1);
else
return (T) new Length(v1 * u1.factor() + v2 * u2.factor(),
LengthUnit.PREFERRED);
}
else
return null; // cannot happen
}
public static <T extends Quantity> T add2(T first, T second) {
if (first instanceof Time(var v1, var u1) && second instanceof Time(var v2, var u2)) {
if (u1 == u2) return (T) new Time(v1 + v2, u1);
else return (T) new Time(v1 * u1.factor() + v2 * u2.factor(), TimeUnit.PREFERRED);
} else if (first instanceof Length(var v1, var u1) && second instanceof Length(var v2, var u2)) {
if (u1 == u2) return (T) new Length(v1 + v2, u1);
else return (T) new Length(v1 * u1.factor() + v2 * u2.factor(), LengthUnit.PREFERRED);
}
else return null; // cannot happen
}
public static void main(String[] args) {
System.out.println(add1(new Time(1, TimeUnit.h), new Time(1, TimeUnit.min)));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't use pattern matching.
FREQUENCY : always
Ubuntu 20.04
OpenJDK Runtime Environment (build 19-ea+25-1892)
A DESCRIPTION OF THE PROBLEM :
A method that uses instanceof pattern matching for records fails with a verify error. Rewriting it with classic instanceof succeeds.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the program below with Java 19.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program runs and prints 3660.0 s
ACTUAL -
Error: Unable to initialize main class Test3
Caused by: java.lang.VerifyError: Bad return type
Exception Details:
Location:
Test3.$proxy$unit(LLength;)LLengthUnit; @4: areturn
Reason:
Type 'QuantityUnit' (current frame, stack[0]) is not assignable to 'LengthUnit' (from method signature)
Current Frame:
bci: @4
flags: { }
locals: { 'Length' }
stack: { 'QuantityUnit' }
Bytecode:
0000000: 2ab6 001a b04c bb00 0959 2bb6 000b 2bb7
0000010: 000f bf
Exception Handler Table:
bci [0, 4] => handler: 5
Stackmap Table:
same_locals_1_stack_item_frame(@5,Object[#7])
---------- BEGIN SOURCE ----------
interface QuantityUnit {
double factor();
}
enum LengthUnit implements QuantityUnit {
m(1), cm(0.01), in(0.01 / 2.54);
private final double factor;
public double factor() {
return factor;
}
LengthUnit(double factor) {
this.factor = factor;
}
public static final LengthUnit PREFERRED = m;
}
enum TimeUnit implements QuantityUnit {
s(1), min(60), h(60 * 60);
private final double factor;
public double factor() {
return factor;
}
TimeUnit(double factor) {
this.factor = factor;
}
public static final TimeUnit PREFERRED = s;
}
sealed interface Quantity {
double value();
QuantityUnit unit();
}
record Length(double value, LengthUnit unit) implements Quantity {
public String toString() {
return value() + " " + unit();
}
}
record Time(double value, TimeUnit unit) implements Quantity {
public String toString() {
return value() + " " + unit();
}
}
public class Test3 {
public static <T extends Quantity> T add1(T first, T second) {
if (first instanceof Time && second instanceof Time) {
var v1 = first.value();
var u1 = ((Time) first).unit();
var v2 = second.value();
var u2 = second.unit();
if (u1 == u2)
return (T) new Time(v1 + v2, u1);
else
return (T) new Time(v1 * u1.factor() + v2 * u2.factor(),
TimeUnit.PREFERRED);
}
else if (first instanceof Length && second instanceof Length) {
var v1 = first.value();
var u1 = ((Length) first).unit();
var v2 = second.value();
var u2 = second.unit();
if (u1 == u2)
return (T) new Length(v1 + v2, u1);
else
return (T) new Length(v1 * u1.factor() + v2 * u2.factor(),
LengthUnit.PREFERRED);
}
else
return null; // cannot happen
}
public static <T extends Quantity> T add2(T first, T second) {
if (first instanceof Time(var v1, var u1) && second instanceof Time(var v2, var u2)) {
if (u1 == u2) return (T) new Time(v1 + v2, u1);
else return (T) new Time(v1 * u1.factor() + v2 * u2.factor(), TimeUnit.PREFERRED);
} else if (first instanceof Length(var v1, var u1) && second instanceof Length(var v2, var u2)) {
if (u1 == u2) return (T) new Length(v1 + v2, u1);
else return (T) new Length(v1 * u1.factor() + v2 * u2.factor(), LengthUnit.PREFERRED);
}
else return null; // cannot happen
}
public static void main(String[] args) {
System.out.println(add1(new Time(1, TimeUnit.h), new Time(1, TimeUnit.min)));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't use pattern matching.
FREQUENCY : always
- backported by
-
JDK-8289242 VerifyError with JEP 405 pattern match
- Resolved
-
JDK-8291148 VerifyError with JEP 405 pattern match
- Resolved
-
JDK-8291320 VerifyError with JEP 405 pattern match
- Resolved