Create a new Select Manager and add the given expressions
to its restrictions.

@param  mixed $expr,...
@return SelectManager
967628
function where($expr)
    {
        $select = $this->from();
        foreach (func_get_args() as $expr) {
            $select->where($expr);
        }
        return $select;
    }
1350571
public function aggregate($expr)
    {
        foreach ($expr as $k => $v) {
            if (is_array($v)) {
                if (isset($v['$count_if'])) {
                    unset($v['$count_if'][0]);
                    $v = ['$sum' => ['$cond' => [$v['$count_if'], 1, 0]]];
                } elseif (isset($v['$sum_if'])) {
                    $field = isset($v['$sum_if'][0]) ? $v['$sum_if'][0] : 1;
                    unset($v['$sum_if'][0]);
                    $v = ['$sum' => ['$cond' => [$v['$sum_if'], is_numeric($field) ? (float)$field : '$' . $field, 0]]];
                } elseif (isset($v['$avg_if'])) {
                    $field = isset($v['$avg_if'][0]) ? $v['$avg_if'][0] : 1;
                    unset($v['$avg_if'][0]);
                    $v = ['$avg' => ['$cond' => [$v['$avg_if'], is_numeric($field) ? (float)$field : '$' . $field, 0]]];
                }
                $this->_aggregate[$k] = $v;
                continue;
            }

            if (preg_match('#^(\w+)\((.*)\)$#', $v, $match) !== 1) {
                throw new MisuseException(['`:aggregate` aggregate is invalid.', 'aggregate' => $v]);
            }

            $accumulator = strtolower($match[1]);
            $normalizes = ['group_concat' => 'push',
                'std' => 'stdDevPop',
                'stddev' => 'stdDevPop',
                'stddev_pop' => 'stdDevPop',
                'stddev_samp' => 'stdDevSamp',
                'addtoset' => 'addToSet',
                'stddevpop' => 'stdDevPop',
                'stddevsamp' => 'stdDevSamp'];
            if (isset($normalizes[$accumulator])) {
                $accumulator = $normalizes[$accumulator];
            }
            $operand = $match[2];
            if ($accumulator === 'count') {
                $this->_aggregate[$k] = ['$sum' => 1];
            } elseif ($accumulator === 'count_if') {
                if ($cond = $this->_compileCondExpression($operand)) {
                    $this->_aggregate[$k] = ['$sum' => $cond];
                } else {
                    throw new MisuseException(['unknown COUNT_IF expression: `:expression`', 'expression' => $operand]);
                }
            } elseif ($accumulator === 'sum_if') {
                if ($cond = $this->_compileCondExpression($operand)) {
                    $this->_aggregate[$k] = ['$sum' => $cond];
                } else {
                    throw new MisuseException(['unknown SUM_IF expression: `:expression`', 'expression' => $operand]);
                }
            } elseif ($accumulator === 'avg_if') {
                if ($cond = $this->_compileCondExpression($operand)) {
                    $this->_aggregate[$k] = ['$avg' => $cond];
                } else {
                    throw new MisuseException(['unknown AVG_IF expression: `:expression`', 'expression' => $operand]);
                }
            } elseif (in_array($accumulator, ['avg', 'first', 'last', 'max', 'min', 'push', 'addToSet', 'stdDevPop', 'stdDevSamp', 'sum'], true)) {
                if (preg_match('#^[\w\.]+$#', $operand) === 1) {
                    $this->_aggregate[$k] = ['$' . $accumulator => '$' . $operand];
                } elseif (preg_match('#^([\w\.]+)\s*([\+\-\*/%])\s*([\w\.]+)$#', $operand, $match2) === 1) {
                    $operator_map = ['+' => '$add', '-' => '$subtract', '*' => '$multiply', '/' => '$divide', '%' => '$mod'];
                    $sub_operand = $operator_map[$match2[2]];
                    $sub_operand1 = is_numeric($match2[1]) ? (float)$match2[1] : ('$' . $match2[1]);
                    $sub_operand2 = is_numeric($match2[3]) ? (float)$match2[3] : ('$' . $match2[3]);
                    $this->_aggregate[$k] = ['$' . $accumulator => [$sub_operand => [$sub_operand1, $sub_operand2]]];
                } elseif ($cond = $this->_compileCondExpression($operand)) {
                    $this->_aggregate[$k] = ['$' . $accumulator => $this->_compileCondExpression($operand)];
                } else {
                    throw new MisuseException(['unknown `:operand` operand of `:aggregate` aggregate', 'operand' => $operand, 'aggregate' => $v]);
                }
            } else {
                throw new MisuseException([
                    'unknown `:accumulator` accumulator of `:aggregate` aggregate',
                    'accumulator' => $accumulator,
                    'aggregate' => $v
                ]);
            }
        }

        return $this->execute();
    }
176656
function where($expr)
    {
        foreach (func_get_args() as $expr) {
            $this->getNodes()->restrictions[] = $expr;
        }

        return $this;
    }
687632
public function addOperator($expression) {
        /**
         * SELECT DISTINCT subject FROM statements WHERE
         */
        $this->query .= '(' .
                $this->getDriverEscaper()->dbCommand('SELECT') . ' ' .
                $this->getDriverEscaper()->dbCommand('DISTINCT') . ' ' .
                $this->getDriverEscaper()->reserved('subject') . ' ' .
                $this->getDriverEscaper()->dbCommand('FROM') . ' ' .
                $this->getDriverEscaper()->reserved($this->options['table']) . ' ' .
                $this->getDriverEscaper()->dbCommand('WHERE') .
                $this->operationSeparator .
                $this->userLanguage . ' ' . $expression;

        if (!empty($this->model)) {
            $this->query .=  $this->getDriverEscaper()->dbCommand('AND') . ' '.
                $this->getDriverEscaper()->reserved('modelid') . ' '.
                $this->getDriverEscaper()->dbCommand('IN') . ' '.
                '(' . implode(',', $this->model->getReadableModels()) . ')'.
                $this->operationSeparator ;
        }
        $this->query .= ' )'.')';

        $this->predicateLoop ++;

        return $this;
    }
173278
private function getSubtree(TreeExpression $expr)
    {
        foreach ($expr->getChildren() as $child) {
            if ($child->getType() == $this->operator)
                return $child;
        }

        $expr->addChild($subtree = new TreeExpression($this->operator));
        return $subtree;
    }
1190439
public function handler($handler)
    {

        if ($this->isNumber($handler) || $this->isBoolean($handler) || $this->isEmpty($handler)) {
            throw new EventManagerException(EventManagerException::INVALID_EVENT_HANDLER);
        }

        if ($this->isString($handler) || $this->isStringObject($handler)) {
            $handler = StdObjectWrapper::toString($handler);
            if (!class_exists($handler)) {
                throw new EventManagerException(EventManagerException::INVALID_EVENT_HANDLER);
            }
            $handler = new $handler;
        }
        $this->handler = $handler;

        return $this;
    }
160320
public function Select( $Func = null )
	{

		if ( $Func == null ) return $this;

		$Func = new Expression( $Func );

		$obj = $this->getClone();

        foreach ( $obj->repository as &$item )
            $item = $Func->execute( $item );

		return $obj;

	}
1300922
public function leaveExpression(Expression $expr)
    {
        if ($expr instanceof OrX || $expr instanceof AndX) {
            $hash = spl_object_hash($expr);

            if ($expr instanceof OrX) {
                $composite = $this->qb->expr()->orX();
                $composite->addMultiple($this->map[$hash]);
            } else {
                $composite = $this->qb->expr()->andX();
                $composite->addMultiple($this->map[$hash]);
            }

            unset($this->hashes[array_search($hash, $this->hashes)]);

            if (!count($this->hashes)) {
                $this->qb->andWhere($composite);
            } else {
                $lastHash = end($this->hashes);

                $this->map[$lastHash][] = $composite;
            }
        }

        return $expr;
    }
869023
public static JSTypeExpression makeOptionalArg(JSTypeExpression expr) {
    if (expr.isOptionalArg() || expr.isVarArgs()) {
      return expr;
    } else {
      return new JSTypeExpression(
          new Node(Token.EQUALS, expr.root), expr.sourceName);
    }
  }
1160356
public static function parseEventExpr($expr)
    {
        if (!preg_match('#^([\w*.,]+)(/([\w*.,]+)(/([\w*.,]+))?)?$#i', $expr, $matches)) {
            throw new \InvalidArgumentException('The expression must be in the format "topic/event?/version?"');
        }

        $topic = $matches[1];
        $event = isset($matches[3]) ? $matches[3] : '*';
        $version = isset($matches[5]) ? $matches[5] : '*';

        if ($topic === '*') {
            $event = $version = '*';
        } elseif ($event === '*') {
            $version = '*';
        }

        return [
            'topic' => $topic,
            'event' => $event,
            'version' => $version,
        ];
    }
118614
function on($expr)
    {
        $lastJoin = $this->getLastJoinSource();

        // Join all given expressions with AND
        if ($lastJoin->right instanceof On) {
            // Merge the new ON Expressions with the 
            // old if there exists an ON Expression
            $lastJoin->right->expression = $expr;
        } else {
            // Otherwise create a new ON Expression
            $lastJoin->right = new On($expr);
        }
        return $this;
    }
164817
protected function _selector_an_plus_b($expr, $last = false)
    {
        $expr = preg_replace("/\s/", "", $expr);
        if (!preg_match("/^(?P<a>-?[0-9]*)?n(?P<b>[-+]?[0-9]+)?$/", $expr, $matches)) {
            return "false()";
        }

        $a = ((isset($matches["a"]) && $matches["a"] !== "") ? intval($matches["a"]) : 1);
        $b = ((isset($matches["b"]) && $matches["b"] !== "") ? intval($matches["b"]) : 0);

        $position = ($last ? "(last()-position()+1)" : "position()");

        if ($b == 0) {
            return "($position mod $a) = 0";
        } else {
            $compare = (($a < 0) ? "<=" : ">=");
            $b2 = -$b;
            if ($b2 >= 0) {
                $b2 = "+$b2";
            }
            return "($position $compare $b) and ((($position $b2) mod " . abs($a) . ") = 0)";
        }
    }
981027
public function compileExpression(QueryBuilder $queryBuilder, Expr $expr, bool $subSelectAlias = false)
    {
        switch (true) {
            case $expr instanceof Expression\Count:
                return $this->doctrinePlatform->getCountExpression('*');

            case $expr instanceof Expression\SimpleAggregate:
                return $this->compileSimpleAggregate($queryBuilder, $expr);

            case $expr instanceof Expression\BinOp:
                return (string)$this->compileBinOp($queryBuilder, $expr);

            case $expr instanceof Expression\ColumnExpr:
                return ''
                . $this->doctrinePlatform->quoteSingleIdentifier($expr->getTable())
                . '.'
                . $this->doctrinePlatform->quoteSingleIdentifier($expr->getName());

            case $expr instanceof Expression\Parameter:
                return $queryBuilder->createPositionalParameter($this->platform->mapValueToDbFormat($expr->getType(), $expr->getValue()));

            case $expr instanceof Expression\Tuple:
                return $this->compileExpressions($queryBuilder, $expr->getExpressions());

            case $expr instanceof Expression\UnaryOp:
                return $this->compileUnaryOp($queryBuilder, $expr);

            case $expr instanceof Expression\SubSelect:
                return $this->compileSubSelect($queryBuilder, $expr, $subSelectAlias);
        }

        throw InvalidArgumentException::format('Unknown expression type: ' . get_class($expr));
    }
1279015
private function buildExpressionForSelector(string $selector)
    {

        if ($expression = $this->resultCache->fetch($selector)) {
            return $expression;
        }

        try {
            $expression = $this->cssConverter->toXPath($selector);
        } catch (ExpressionErrorException $expressionErrorException) {

            // Allow for pseudo selectors
            // TODO: Find a way to validate this exception without checking strings
            if ($expressionErrorException->getMessage() !== 'Pseudo-elements are not supported.') {
                return false;
            }

            try {
                $tokens = explode(':', $selector);
                $expression = $this->cssConverter->toXPath((string)reset($tokens));
            } catch (Exception $e) {
                return false;
            }

        } catch (ExceptionInterface $e) {
            return false;
        }


        $this->resultCache->save($selector, $expression);

        return $expression;
    }
346490
public function dispatch(Expression $expr)
    {
        switch (true) {
            case $expr instanceof Comparison:
                return $this->walkComparison($expr);
            case $expr instanceof Value:
                return $this->walkValue($expr);
            case $expr instanceof CompositeExpression:
                return $this->walkCompositeExpression($expr);
            default:
                throw new RuntimeException('Unknown Expression ' . get_class($expr));
        }
    }
682281
public function resolveExpressionNodeToType($expr)
    {
        // PARENTHESIZED EXPRESSION
        // Retrieve inner expression from parenthesized expression
        while ($expr instanceof Node\Expression\ParenthesizedExpression) {
            $expr = $expr->expression;
        }

        if ($expr == null || $expr instanceof PhpParser\MissingToken || $expr instanceof PhpParser\SkippedToken) {
            // TODO some members are null or Missing/SkippedToken
            // How do we handle this more generally?
            return new Types\Mixed_;
        }

        // VARIABLE
        //   $this -> Type\this
        //   $myVariable -> type of corresponding assignment expression
        if ($expr instanceof Node\Expression\Variable || $expr instanceof Node\UseVariableName) {
            if ($expr->getName() === 'this') {
                return new Types\Object_(new Fqsen('\\' . $this->getContainingClassFqn($expr)));
            }
            // Find variable definition (parameter or assignment expression)
            $defNode = $this->resolveVariableToNode($expr);
            if ($defNode instanceof Node\Expression\AssignmentExpression || $defNode instanceof Node\UseVariableName) {
                return $this->resolveExpressionNodeToType($defNode);
            }
            if ($defNode instanceof Node\ForeachKey || $defNode instanceof Node\ForeachValue) {
                return $this->getTypeFromNode($defNode);
            }
            if ($defNode instanceof Node\Parameter) {
                return $this->getTypeFromNode($defNode);
            }
        }

        // FUNCTION CALL
        // Function calls are resolved to type corresponding to their FQN
        if ($expr instanceof Node\Expression\CallExpression &&
            !(
                $expr->callableExpression instanceof Node\Expression\ScopedPropertyAccessExpression ||
                $expr->callableExpression instanceof Node\Expression\MemberAccessExpression)
        ) {
            // Find the function definition
            if ($expr->callableExpression instanceof Node\Expression) {
                // Cannot get type for dynamic function call
                return new Types\Mixed_;
            }

            if ($expr->callableExpression instanceof Node\QualifiedName) {
                $fqn = $expr->callableExpression->getResolvedName() ?? $expr->callableExpression->getNamespacedName();
                $fqn .= '()';
                $def = $this->index->getDefinition($fqn, true);
                if ($def !== null) {
                    return $def->type;
                }
            }
        }

        // TRUE / FALSE / NULL
        // Resolve true and false reserved words to Types\Boolean
        if ($expr instanceof Node\ReservedWord) {
            $token = $expr->children->kind;
            if ($token === PhpParser\TokenKind::TrueReservedWord || $token === PhpParser\TokenKind::FalseReservedWord) {
                return new Types\Boolean;
            }

            if ($token === PhpParser\TokenKind::NullReservedWord) {
                return new Types\Null_;
            }
        }

        // CONSTANT FETCH
        // Resolve constants by retrieving corresponding definition type from FQN
        if (ParserHelpers\isConstantFetch($expr)) {
            $fqn = (string)$expr->getNamespacedName();
            $def = $this->index->getDefinition($fqn, true);
            if ($def !== null) {
                return $def->type;
            }
        }

        // MEMBER CALL EXPRESSION/SCOPED PROPERTY CALL EXPRESSION
        //   The type of the member/scoped property call expression is the type of the method, so resolve the
        //   type of the callable expression.
        if ($expr instanceof Node\Expression\CallExpression && (
            $expr->callableExpression instanceof Node\Expression\MemberAccessExpression ||
            $expr->callableExpression instanceof Node\Expression\ScopedPropertyAccessExpression)
        ) {
            return $this->resolveExpressionNodeToType($expr->callableExpression);
        }

        // MEMBER ACCESS EXPRESSION
        if ($expr instanceof Node\Expression\MemberAccessExpression) {
            if ($expr->memberName instanceof Node\Expression) {
                return new Types\Mixed_;
            }
            $var = $expr->dereferencableExpression;

           // Resolve object
            $objType = $this->resolveExpressionNodeToType($var);
            if (!($objType instanceof Types\Compound)) {
                $objType = new Types\Compound([$objType]);
            }
            for ($i = 0; $t = $objType->get($i); $i++) {
                if ($t instanceof Types\This) {
                    $classFqn = self::getContainingClassFqn($expr);
                    if ($classFqn === null) {
                        return new Types\Mixed_;
                    }
                } else if (!($t instanceof Types\Object_) || $t->getFqsen() === null) {
                    return new Types\Mixed_;
                } else {
                    $classFqn = substr((string)$t->getFqsen(), 1);
                }
                $add = '->' . $expr->memberName->getText($expr->getFileContents());
                if ($expr->parent instanceof Node\Expression\CallExpression) {
                    $add .= '()';
                }
                $classDef = $this->index->getDefinition($classFqn);
                if ($classDef !== null) {
                    foreach ($classDef->getAncestorDefinitions($this->index, true) as $fqn => $def) {
                        $def = $this->index->getDefinition($fqn . $add);
                        if ($def !== null) {
                            if ($def->type instanceof Types\This || $def->type instanceof Types\Self_) {
                                return new Types\Object_(new Fqsen('\\' . $classFqn));
                            }
                            return $def->type;
                        }
                    }
                }
            }
        }

        // SCOPED PROPERTY ACCESS EXPRESSION
        if ($expr instanceof Node\Expression\ScopedPropertyAccessExpression) {
            $classType = $this->resolveClassNameToType($expr->scopeResolutionQualifier);
            if (!($classType instanceof Types\Object_) || $classType->getFqsen() === null) {
                return new Types\Mixed_;
            }
            $fqn = substr((string)$classType->getFqsen(), 1) . '::';

            // TODO is there a cleaner way to do this?
            $fqn .= $expr->memberName->getText() ?? $expr->memberName->getText($expr->getFileContents());
            if ($expr->parent instanceof Node\Expression\CallExpression) {
                $fqn .= '()';
            }

            $def = $this->index->getDefinition($fqn);
            if ($def === null) {
                return new Types\Mixed_;
            }
            return $def->type;
        }

        // OBJECT CREATION EXPRESSION
        //   new A() => resolves to the type of the class type designator (A)
        //   TODO: new $this->a => resolves to the string represented by "a"
        if ($expr instanceof Node\Expression\ObjectCreationExpression) {
            return $this->resolveClassNameToType($expr->classTypeDesignator);
        }

        // CLONE EXPRESSION
        //   clone($a) => resolves to the type of $a
        if ($expr instanceof Node\Expression\CloneExpression) {
            return $this->resolveExpressionNodeToType($expr->expression);
        }

        // ASSIGNMENT EXPRESSION
        //   $a = $myExpression => resolves to the type of the right-hand operand
        if ($expr instanceof Node\Expression\AssignmentExpression) {
            return $this->resolveExpressionNodeToType($expr->rightOperand);
        }

        // TERNARY EXPRESSION
        //   $condition ? $ifExpression : $elseExpression => reslves to type of $ifCondition or $elseExpression
        //   $condition ?: $elseExpression => resolves to type of $condition or $elseExpression
        if ($expr instanceof Node\Expression\TernaryExpression) {
            // ?:
            if ($expr->ifExpression === null) {
                return new Types\Compound([
                    $this->resolveExpressionNodeToType($expr->condition), // TODO: why?
                    $this->resolveExpressionNodeToType($expr->elseExpression)
                ]);
            }
            // Ternary is a compound of the two possible values
            return new Types\Compound([
                $this->resolveExpressionNodeToType($expr->ifExpression),
                $this->resolveExpressionNodeToType($expr->elseExpression)
            ]);
        }

        // NULL COALLESCE
        //   $rightOperand ?? $leftOperand => resolves to type of $rightOperand or $leftOperand
        if ($expr instanceof Node\Expression\BinaryExpression && $expr->operator->kind === PhpParser\TokenKind::QuestionQuestionToken) {
            // ?? operator
            return new Types\Compound([
                $this->resolveExpressionNodeToType($expr->leftOperand),
                $this->resolveExpressionNodeToType($expr->rightOperand)
            ]);
        }

        // BOOLEAN EXPRESSIONS: resolve to Types\Boolean
        //   (bool) $expression
        //   !$expression
        //   empty($var)
        //   isset($var)
        //   >, >=, <, <=, &&, ||, AND, OR, XOR, ==, ===, !=, !==
        if (
            ParserHelpers\isBooleanExpression($expr)

            || ($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::BoolCastToken)
            || ($expr instanceof Node\Expression\UnaryOpExpression && $expr->operator->kind === PhpParser\TokenKind::ExclamationToken)
            || $expr instanceof Node\Expression\EmptyIntrinsicExpression
            || $expr instanceof Node\Expression\IssetIntrinsicExpression
        ) {
            return new Types\Boolean;
        }

        // STRING EXPRESSIONS: resolve to Types\String
        //   [concatenation] .=, .
        //   [literals] "hello", \b"hello", \B"hello", 'hello', \b'hello', HEREDOC, NOWDOC
        //   [cast] (string) "hello"
        //
        //   TODO: Magic constants (__CLASS__, __DIR__, __FUNCTION__, __METHOD__, __NAMESPACE__, __TRAIT__, __FILE__)
        if (
            ($expr instanceof Node\Expression\BinaryExpression &&
                ($expr->operator->kind === PhpParser\TokenKind::DotToken || $expr->operator->kind === PhpParser\TokenKind::DotEqualsToken)) ||
            $expr instanceof Node\StringLiteral ||
            ($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::StringCastToken)
        ) {
            return new Types\String_;
        }

        // BINARY EXPRESSIONS:
        // Resolve to Types\Integer if both left and right operands are integer types, otherwise Types\Float
        //   [operator] +, -, *, **
        //   [assignment] *=, **=, -=, +=
        // Resolve to Types\Float
        //   [assignment] /=
        if (
            $expr instanceof Node\Expression\BinaryExpression &&
            ($operator = $expr->operator->kind)
            && ($operator === PhpParser\TokenKind::PlusToken ||
                $operator === PhpParser\TokenKind::AsteriskAsteriskToken ||
                $operator === PhpParser\TokenKind::AsteriskToken ||
                $operator === PhpParser\TokenKind::MinusToken ||

                // Assignment expressions (TODO: consider making this a type of AssignmentExpression rather than kind of BinaryExpression)
                $operator === PhpParser\TokenKind::AsteriskEqualsToken||
                $operator === PhpParser\TokenKind::AsteriskAsteriskEqualsToken ||
                $operator === PhpParser\TokenKind::MinusEqualsToken ||
                $operator === PhpParser\TokenKind::PlusEqualsToken
            )
        ) {
            if (
                $this->resolveExpressionNodeToType($expr->leftOperand) instanceof Types\Integer
                && $this->resolveExpressionNodeToType($expr->rightOperand) instanceof Types\Integer
            ) {
                return new Types\Integer;
            }
            return new Types\Float_;
        } else if (
            $expr instanceof Node\Expression\BinaryExpression &&
            $expr->operator->kind === PhpParser\TokenKind::SlashEqualsToken
        ) {
            return new Types\Float_;
        }

        // INTEGER EXPRESSIONS: resolve to Types\Integer
        //   [literal] 1
        //   [operator] <=>, &, ^, |
        //   TODO: Magic constants (__LINE__)
        if (
            // TODO: consider different Node types of float/int, also better property name (not "children")
            ($expr instanceof Node\NumericLiteral && $expr->children->kind === PhpParser\TokenKind::IntegerLiteralToken) ||
            $expr instanceof Node\Expression\BinaryExpression && (
                ($operator = $expr->operator->kind)
                && ($operator === PhpParser\TokenKind::LessThanEqualsGreaterThanToken ||
                    $operator === PhpParser\TokenKind::AmpersandToken ||
                    $operator === PhpParser\TokenKind::CaretToken ||
                    $operator === PhpParser\TokenKind::BarToken)
            )
        ) {
            return new Types\Integer;
        }

        // FLOAT EXPRESSIONS: resolve to Types\Float
        //   [literal] 1.5
        //   [operator] /
        //   [cast] (double)
        if (
            $expr instanceof Node\NumericLiteral && $expr->children->kind === PhpParser\TokenKind::FloatingLiteralToken ||
            ($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::DoubleCastToken) ||
            ($expr instanceof Node\Expression\BinaryExpression && $expr->operator->kind === PhpParser\TokenKind::SlashToken)
        ) {
            return new Types\Float_;
        }

        // ARRAY CREATION EXPRESSION:
        // Resolve to Types\Array (Types\Compound of value and key types)
        //  [a, b, c]
        //  [1=>"hello", "hi"=>1, 4=>[]]s
        if ($expr instanceof Node\Expression\ArrayCreationExpression) {
            $valueTypes = [];
            $keyTypes = [];
            if ($expr->arrayElements !== null) {
                foreach ($expr->arrayElements->getElements() as $item) {
                    $valueTypes[] = $this->resolveExpressionNodeToType($item->elementValue);
                    $keyTypes[] = $item->elementKey ? $this->resolveExpressionNodeToType($item->elementKey) : new Types\Integer;
                }
            }
            $valueTypes = array_unique($valueTypes);
            $keyTypes = array_unique($keyTypes);
            if (empty($valueTypes)) {
                $valueType = null;
            } else if (count($valueTypes) === 1) {
                $valueType = $valueTypes[0];
            } else {
                $valueType = new Types\Compound($valueTypes);
            }
            if (empty($keyTypes)) {
                $keyType = null;
            } else if (count($keyTypes) === 1) {
                $keyType = $keyTypes[0];
            } else {
                $keyType = new Types\Compound($keyTypes);
            }
            return new Types\Array_($valueType, $keyType);
        }

        // SUBSCRIPT EXPRESSION
        // $myArray[3]
        // $myArray{"hello"}
        if ($expr instanceof Node\Expression\SubscriptExpression) {
            $varType = $this->resolveExpressionNodeToType($expr->postfixExpression);
            if (!($varType instanceof Types\Array_)) {
                return new Types\Mixed_;
            }
            return $varType->getValueType();
        }

        // SCRIPT INCLUSION EXPRESSION
        //   include, require, include_once, require_once
        if ($expr instanceof Node\Expression\ScriptInclusionExpression) {
            // TODO: resolve path to PhpDocument and find return statement
            return new Types\Mixed_;
        }

        if ($expr instanceof Node\QualifiedName) {
            return $this->resolveClassNameToType($expr);
        }

        return new Types\Mixed_;
    }
153415
protected function getExpressionInSelect(Select $select, string $tableAlias) : Expr
    {
        return $this->loadExpressionWithNecessarySubselects($select, $tableAlias, function (Select $select, $tableAlias) {
            return $this->getSingleValueExpressionInSelect($select, $tableAlias);
        });
    }