/**
  * Helper Constructor.
  *
  * This is called when we join two flow scope chains. For example, when we combine the outcomes of the ON_TRUE
  * and the ON_FALSE branch of an IF clause.
  *
  * @param \Scrutinizer\PhpAnalyzer\DataFlow\TypeInference\LinkedFlowScope $joinedScopeA
  * @param \Scrutinizer\PhpAnalyzer\DataFlow\TypeInference\LinkedFlowScope $joinedScopeB
  *
  * @return FlatFlowScopeCache
  */
 public static function createFromLinkedScopes(LinkedFlowScope $joinedScopeA, LinkedFlowScope $joinedScopeB)
 {
     $cache = new self();
     // Always prefer the "real" scope to the faked-out bottom scope.
     $cache->functionScope = $joinedScopeA->flowsFromBottom() ? $joinedScopeB->getFunctionScope() : $joinedScopeA->getFunctionScope();
     $slotsA = $cache->symbols = $joinedScopeA->allFlowSlots();
     $slotsB = $joinedScopeB->allFlowSlots();
     // There are 5 different join cases:
     // 1) The type is declared in joinedScopeA, not in joinedScopeB,
     //    and not in functionScope. Just use the one in A.
     // 2) The type is declared in joinedScopeB, not in joinedScopeA,
     //    and not in functionScope. Just use the one in B.
     // 3) The type is declared in functionScope and joinedScopeA, but
     //    not in joinedScopeB. Join the two types.
     // 4) The type is declared in functionScope and joinedScopeB, but
     //    not in joinedScopeA. Join the two types.
     // 5) The type is declared in joinedScopeA and joinedScopeB. Join
     //    the two types.
     $symbolNames = array_unique(array_merge(array_keys($slotsA), array_keys($slotsB)));
     foreach ($symbolNames as $name) {
         $slotA = isset($slotsA[$name]) ? $slotsA[$name] : null;
         $slotB = isset($slotsB[$name]) ? $slotsB[$name] : null;
         $joinedType = null;
         if (null === $slotB || $slotB->getType() === null) {
             $fnSlot = $joinedScopeB->getFunctionScope()->getVar($name);
             $fnSlotType = null === $fnSlot ? null : $fnSlot->getType();
             if (null === $fnSlotType) {
                 // Case #1 -- The symbol was already inserted from A slots.
             } else {
                 // Case #3
                 $joinedType = $slotA->getType()->getLeastSuperType($fnSlotType);
             }
         } else {
             if (null === $slotA || $slotA->getType() === null) {
                 $fnSlot = $joinedScopeA->getFunctionScope()->getVar($name);
                 $fnSlotType = null === $fnSlot ? null : $fnSlot->getType();
                 if (null === $fnSlotType) {
                     // Case #2
                     $cache->symbols[$name] = $slotB;
                 } else {
                     // Case #4
                     $joinedType = $slotB->getType()->getLeastSuperType($fnSlotType);
                 }
             } else {
                 // Case #5
                 $joinedType = $slotA->getType()->getLeastSuperType($slotB->getType());
             }
         }
         if (null !== $joinedType) {
             $cache->symbols[$name] = new SimpleSlot($name, $joinedType, true);
         }
     }
     return $cache;
 }