private function assertUnion($expected)
 {
     $builder = new UnionTypeBuilder($this->registry);
     $types = func_get_args();
     $types = array_splice($types, 1);
     foreach ($types as $type) {
         $type = $this->resolveType($type);
         $builder->addAlternate($type);
     }
     $this->assertEquals($expected, (string) $builder->build());
 }
 private function inferTypeForParameter(AbstractFunction $function, Parameter $param)
 {
     $builder = new UnionTypeBuilder($this->typeRegistry);
     $index = $param->getIndex();
     foreach ($function->getInCallSites() as $site) {
         $args = $site->getArgs();
         if (!isset($args[$index])) {
             continue;
         }
         $builder->addAlternate($args[$index]->getPhpType());
     }
     $newType = $builder->build();
     if (!$newType->isNoType() && !$newType->isUnknownType()) {
         $param->setPhpType($newType);
     }
 }
 private function checkParameterAssignment(\PHPParser_Node_Param $node)
 {
     $builder = new UnionTypeBuilder($this->typeRegistry);
     if (null !== $node->default) {
         $this->attachLiteralTypes($node->default);
         $type = $node->default->getAttribute('type');
         if ($type) {
             $builder->addAlternate($type);
         }
     }
     if ('array' === $node->type) {
         $type = $this->typeRegistry->getNativeType('array');
         // If the annotated type also contains the array type, we use the annotated
         // type as it is potentially more specific, e.g. "array<string>" or "array|null".
         $annotatedType = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name);
         if (null !== ($containedArrayType = $this->getContainedArrayType($annotatedType))) {
             $type = $containedArrayType;
         }
         $builder->addAlternate($type);
     } else {
         if ($node->type instanceof \PHPParser_Node_Name) {
             $builder->addAlternate($this->typeRegistry->getClassOrCreate(implode("\\", $node->type->parts)));
         }
     }
     $type = $builder->build();
     if ($type->isNoType()) {
         $type = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name);
     } else {
         if ($type->isNullType()) {
             $commentType = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name);
             if ($commentType) {
                 $type = $this->typeRegistry->createNullableType($commentType);
             } else {
                 $type = null;
             }
         } else {
             if ($type->isBooleanType()) {
                 $commentType = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name);
                 if ($commentType) {
                     $type = $this->typeRegistry->createUnionType(array($type, $commentType));
                 }
             }
         }
     }
     if (null === $type) {
         $type = $this->typeRegistry->getNativeType('unknown');
     }
     $node->setAttribute('type', $type);
     // This could be the case if the same name is used twice as parameter.
     if (false === $this->scope->isDeclared($node->name)) {
         $var = $this->scope->declareVar($node->name, $type, null === $type);
         $var->setNameNode($node);
         $var->setReference($node->byRef);
     } else {
         $var = $this->scope->getVar($node->name);
         if ($varType = $var->getType()) {
             $var->setType($this->typeRegistry->createUnionType(array($varType, $type)));
         } else {
             if (null !== $type) {
                 $var->setType($type);
                 $var->setTypeInferred(true);
             }
         }
         $var->setReference($node->byRef);
     }
 }
 /**
  * Creates a new union with the given types.
  *
  * If strings are passed, they are assumed to be native types.
  *
  * @param array $types
  *
  * @return UnionType
  */
 public function createUnionType(array $types)
 {
     $builder = new UnionTypeBuilder($this);
     foreach ($types as $type) {
         if (!$type instanceof PhpType) {
             $nativeType = $this->getNativeType($type);
             if (null === $nativeType) {
                 throw new \InvalidArgumentException(sprintf('There is no native type named "%s".', $type));
             }
             $type = $nativeType;
         }
         assert($type instanceof PhpType);
         $builder->addAlternate($type);
     }
     return $builder->build();
 }
 public function enterScope(NodeTraversal $t)
 {
     $scope = $t->getScope();
     $root = $scope->getRootNode();
     if (!$root instanceof \PHPParser_Node_Stmt_Function && !$root instanceof \PHPParser_Node_Stmt_ClassMethod) {
         return;
     }
     // Bail out on abstract methods.
     if ($root instanceof \PHPParser_Node_Stmt_ClassMethod && ($root->type & \PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT) !== 0) {
         return;
     }
     // Bail out on methods defined on interfaces.
     if ($root instanceof \PHPParser_Node_Stmt_ClassMethod && $root->getAttribute('parent')->getAttribute('parent') instanceof \PHPParser_Node_Stmt_Interface) {
         return;
     }
     // Bail out on built-in functions marked by the @jms-builtin annotation.
     // For these, we will solely infer types from doc comments.
     if (false !== strpos($root->getDocComment(), '@jms-builtin')) {
         return;
     }
     // Same as above, but for methods of classes marked with @jms-builtin.
     if ($root instanceof \PHPParser_Node_Stmt_ClassMethod) {
         $maybeClass = $root->getAttribute('parent')->getAttribute('parent');
         if ($maybeClass instanceof \PHPParser_Node_Stmt_Class && false !== strpos($maybeClass->getDocComment(), '@jms-builtin')) {
             return;
         }
     }
     $cfg = $t->getControlFlowGraph();
     $builder = new UnionTypeBuilder($this->typeRegistry);
     foreach ($cfg->getNode(null)->getInEdges() as $edge) {
         $sourceNode = $edge->getSource()->getAstNode();
         if (!$sourceNode instanceof \PHPParser_Node_Stmt_Return) {
             $builder->addAlternate($this->typeRegistry->getNativeType('null'));
             continue;
         }
         // If there is no type information available, we cannot make any
         // assumptions for this function/method.
         if (!($type = $sourceNode->getAttribute('type'))) {
             return;
         }
         $builder->addAlternate($type);
     }
     $type = $builder->build();
     if ($type->isUnknownType()) {
         return;
     }
     $function = $this->typeRegistry->getFunctionByNode($root);
     if ($function instanceof GlobalFunction) {
         if ($this->hasTypeChanged($type, $function->getReturnType())) {
             $this->repeatedPass->repeat();
         }
         $function->setReturnType($type);
     } else {
         if ($function instanceof ContainerMethodInterface) {
             $method = $function->getMethod();
             if ($this->hasTypeChanged($type, $method->getReturnType())) {
                 $this->repeatedPass->repeat();
             }
             $method->setReturnType($type);
         }
     }
 }