public function equals(LatticeElementInterface $that)
 {
     if (!$that instanceof LinkedFlowScope) {
         return false;
     }
     if ($this->optimize() === $that->optimize()) {
         return true;
     }
     // If two flow scopes are in the same function, then they could have two possible function scopes:
     //   1) the real function scope, or
     //   2) the BOTTOM scope.
     // If they have different function scopes, we theoretically should iterate through all the variable in each
     // scope and compare. However, 99.9% of the time, they're not equal. The other 0.1% of the time, we can just
     // assume that they are equal. Eventually, it just means that data flow analysis has to propagate the entry
     // lattice a bit further than it really needs to, but the end result is not affected.
     if ($this->getFunctionScope() !== $that->getFunctionScope()) {
         return false;
     }
     if ($this->cache === $that->cache) {
         // If the two flow scopes have the same cache, then we can check equality a lot faster: by just looking at
         // the "dirty" elements in the cache, and comparing them in both scopes.
         foreach ($this->cache->dirtySymbols as $name) {
             if ($this->diffSlots($this->getSlot($name), $that->getSlot($name))) {
                 return false;
             }
         }
         return true;
     }
     $myFlowSlots = $this->allFlowSlots();
     $otherFlowSlots = $that->allFlowSlots();
     foreach ($myFlowSlots as $name => $slot) {
         if ($this->diffSlots($slot, isset($otherFlowSlots[$name]) ? $otherFlowSlots[$name] : null)) {
             return false;
         }
         unset($otherFlowSlots[$name]);
     }
     foreach ($otherFlowSlots as $name => $slot) {
         if ($this->diffSlots($slot, isset($myFlowSlots[$name]) ? $myFlowSlots[$name] : null)) {
             return false;
         }
     }
     return true;
 }