In Simple and Effective Type Check Removal through Lazy Basic Block Versioning, which introduces Lazy Basic Block Versioning (LBBV), they have runtime type checks expand into two thunks for the cases that the type check passes or fails; forcing the type check pass thunk emits a block which is specialized with knowledge that the variable is the given type.
However, they only propagate specific and positive types this way. In the type check failure case they don't track the knowledge that the variable isn't the given type, which causes things like diagram 3.4 having duplicate type checks for is_i32(i) at both block B and J, even though block J is dominated by the type check of block B.
Indeed, in section 3.3 "Flow-based Representation Analysis" they implement a static type propagation pass to compare the performance of LBBV against which does implement set-based type information, including negative sets, and point out that this analysis is richer than the strictly precise type tags that LBBV uses.
Why doesn't LBBV track type sets? Does the block versioning scheme fall apart with the introduction of negative sets, or cause the trace to explode in number of blocks? Is it simply a runtime performance trade-off?
i32". Given that this is a research article, the authors may have thought it was more important to investigate their technique's effectiveness in the more typical scenario where negative types aren't possible. But unless they have explained this choice in the paper itself, then this question can only really be answered by the authors themselves; I would suggest sending a brief email (and perhaps including their response in an answer here). $\endgroup$