Class LatticeJoin

java.lang.Object
org.ek9lang.compiler.phase5.flow.LatticeJoin

final class LatticeJoin extends Object
THE join of the value-tracking lattice: the least upper bound of two values at a branch convergence point.

Every AbstractValue.join(AbstractValue) delegates here, so there is ONE table and a join can never depend on which branch happens to be written (or analysed) first. Each pair of different kinds is decided in exactly one place: the two values are put in a fixed order of kind before the table is consulted. Two values of the same kind keep the order they were given in (only a lock identity can notice: its token list is a union in the order met).

The rules:

  • BOTTOM (unreachable) is ignored: BOTTOM join X = X.
  • TOP absorbs: TOP join X = TOP.
  • A constant and a range join to the range that covers both (an integer constant); any other constant against a range is TOP.
  • A SET state - a SetStateValue or a CollectionStateValue that is set - against a constant, range or excluded constant is SET: both branches deliver a set value, and nothing more is known (D42 - it once answered the precise value, so the other branch's values were claimed impossible). An UNSET state disagrees with all of them (TOP). Keeping what is known when a value is PROVEN set (if x?) is a narrowing, ValueTrackingAnalyzer.narrowForIsSet(ISymbol, boolean), never a join.
  • A lock identity joins only with another lock identity (union of the tokens); against anything else it is TOP, deliberately, because a SET branch must not collapse to one lock.
  • A symbolic term joins only with the term of the same name.

Every answer is an UPPER BOUND of its two arguments in LatticeOrder, THE order of the lattice: whatever either branch can deliver, the joined value still admits (LatticeJoinTest pins it over every pair). Precision is only ever gained by narrowing, never by a join.