boolean (@NotNull DfaMemoryState other) { if (!(other instanceof DfaMemoryStateImpl that)) return false; if (myEphemeral && !that.myEphemeral) return false; if (myStack.size() != that.myStack.size()) return false; for (int i = 0; i < myStack.size(); i++) { if (!isSuperValue(myStack.get(i), that.myStack.get(i))) return false; } int[] thisToThat = getClassesMap(that); if (thisToThat == null) return false; for (DistinctPairSet.DistinctPair pair : myDistinctClasses) { int firstIndex = thisToThat[pair.getFirstIndex()]; int secondIndex = thisToThat[pair.getSecondIndex()]; if (firstIndex == -1 || secondIndex == -1 || firstIndex == secondIndex) return false; RelationType relation = that.myDistinctClasses.getRelation(firstIndex, secondIndex); if (relation == null || pair.isOrdered() && relation != RelationType.LT) return false; } for (Map.Entry<DfaVariableValue, DfType> entry : this.myVariableTypes.entrySet()) { DfaVariableValue value = entry.getKey(); DfType thisType = entry.getValue(); // the inherent variable type is not always a superstate for any non-inherent type // (e.g. inherent can be nullable, but current type can be notnull) // so we cannot limit checking to myVariableTypes map only DfType thatType = that.getDfType(value); if(!thisType.isMergeable(thatType)) return false; } for (Map.Entry<DfaVariableValue, DfType> entry : that.myVariableTypes.entrySet()) { DfaVariableValue value = entry.getKey(); if (this.myVariableTypes.containsKey(value)) continue; // already processed in the previous loop DfType thisType = this.getDfType(value); DfType thatType = entry.getValue(); if(!thisType.isMergeable(thatType)) return false; } return true; }