/**
  * @param string[] $variableTypes indexed by variable name
  *
  * @return bool
  */
 public function canCauseSideEffects(array $variableTypes) : bool
 {
     if (self::GLOBAL_VAR === $this->variable->name) {
         return true;
     }
     $lastOperation = $this->getLastOperation();
     // @todo any of the following operations on array sub-keys is also to be banished, so we need to consider
     //       any operation on any array key as on "mixed" and re-run this check.
     if (null === $lastOperation) {
         return false;
     }
     $isScalar = $this->isScalarType($variableTypes);
     if ($lastOperation instanceof Node\Expr\Cast\String_ && !$isScalar) {
         return true;
     }
     if ($lastOperation instanceof Node\Expr\Cast) {
         return false;
     }
     if ($lastOperation instanceof Node\Expr\Cast\String_ && $isScalar) {
         return false;
     }
     if ($lastOperation instanceof Node\Expr\ArrayDimFetch && $isScalar) {
         // checking parent operation, since we can't have any assumptions on any of the types
         // of the array keys, we have to check the operations applied to that array key for side-effects
         $parentCheck = new self(new Variable(uniqid('surrogateVariableNameForTheArrayDimFetch', true)), array_slice($this->parentOperations, 0, count($this->parentOperations) - 1));
         return $parentCheck->canCauseSideEffects($variableTypes);
     }
     if (($lastOperation instanceof Node\Expr\BinaryOp\Concat || $lastOperation instanceof Node\Expr\AssignOp\Concat) && !$isScalar) {
         return true;
     }
     if ($lastOperation instanceof Node\Expr\BinaryOp || $lastOperation instanceof Node\Expr\AssignOp) {
         return false;
     }
     return !($lastOperation instanceof Return_ || $lastOperation instanceof Node\Expr\Assign);
 }