/** * @param callable $function * @param array $variableTypeMap * @param mixed $expression * * @return ITypeAnalysis */ protected function getAnalysis(callable $function, array $variableTypeMap = [], &$expression = null) { $reflection = $this->functionInterpreter->getReflection($function); foreach ($reflection->getSignature()->getParameterExpressions() as $parameterExpression) { $variableTypeMap[$parameterExpression->getName()] = $this->typeSystem->getTypeFromTypeHint($parameterExpression->getTypeHint()); } $analysisContext = $this->expressionAnalyser->createAnalysisContext($reflection->asEvaluationContext()); foreach ($variableTypeMap as $variable => $type) { $analysisContext->setExpressionType(O\Expression::variable(O\Expression::value($variable)), $type); } $bodyExpressions = $this->functionInterpreter->getStructure($reflection)->getBodyExpressions(); foreach ($bodyExpressions as $expression) { if ($expression instanceof O\ReturnExpression) { return $this->expressionAnalyser->analyse($analysisContext, $expression->getValue()); } elseif (count($bodyExpressions) === 1) { return $this->expressionAnalyser->analyse($analysisContext, $expression); } else { $this->expressionAnalyser->analyse($analysisContext, $expression); } } }
public function visitClosure(O\ClosureExpression $expression) { $originalContext = $this->analysisContext; $this->analysisContext = $originalContext->inNewScope(); foreach ($expression->getParameters() as $parameter) { $this->walk($parameter); $typeHintType = $this->typeSystem->getTypeFromTypeHint($parameter->getTypeHint()); if (!$parameter->hasDefaultValue() || $this->analysis[$parameter->getDefaultValue()]->isEqualTo($typeHintType)) { $this->analysisContext->setExpressionType($parameter->asVariable(), $typeHintType); } else { $this->analysisContext->setExpressionType($parameter->asVariable(), $this->typeSystem->getNativeType(INativeType::TYPE_MIXED)); } } foreach ($expression->getUsedVariables() as $usedVariable) { $variable = $usedVariable->asVariable(); //TODO: handle references with used variables. Probably impossible though. $this->analysisContext->setExpressionType($variable, $originalContext->getExpressionType($variable)); } $this->walkAll($expression->getBodyExpressions()); $this->analysis[$expression] = $this->typeSystem->getObjectType('Closure'); $this->analysisContext = $originalContext; }