"Inconsistent stackmap frames at branch target" in case

Description

Original report: https://ask.clojure.org/index.php/9522/inconsistent-stackmap-frames-branch-providing-primitive and https://gist.github.com/WickedShell/2acaaf5e40a15352123e2bad338e06ae

This throws with a VerifyError:

Analysis

CaseExpr is emitting invalid code when there is a primitive and a reference type in one of the exit branches.

CaseExpr's answer to getJavaClass() is computed as a union of the exit branches (clauses + default). The calculation is incorrect when there is a NilExpr (for which hasJavaClass == true, but getJavaClass == nil), and a NumberExpr. CaseExpr.getJavaClass ends up claiming the whole expression is a primitive long, instead of a reference type, which causes the verifier to reject the mismatched bytecode.
Primitive expressions are only emitted in certain scenarios, that's why the example code includes a seemingly useless let. Reversing the example above to have a nil default case and a numeric then-branch also avoids this miscalculation.

Approach

Short circuit the decision and answer “this is a reference type expression” (maybeJavaClass returns null) if any of the result expressions claim to be a null Java class.

Patch

clj-2580.patch

Screened by: Alex Miller

Environment

None

Activity

Show:
Alex Miller
September 25, 2020, 7:22 PM

Released in 1.10.2-alpha2

Assignee

Unassigned

Reporter

Alex Miller

Labels

Approval

Ok

Patch

Code and Test

Fix versions

Affects versions

Priority

Major
Configure