private function createVar(LinkedFlowScope $scope, $name, $type)
 {
     $type = $this->registry->resolveType($type);
     $this->functionScope->declareVar($name)->setNameNode($n = new \PHPParser_Node_Expr_Variable($name));
     $scope->inferSlotType($name, $type);
     $n->setAttribute('type', $type);
     return $n;
 }
 public function testDeclareVar()
 {
     $scope = new Scope($this->getMock('PHPParser_Node'));
     $this->assertNull($scope->getVar('x'));
     $scope->declareVar('x', $this->registry->getNativeType('integer'));
     $this->assertNotNull($var = $scope->getVar('x'));
     $this->assertSame($this->registry->getNativeType('integer'), $var->getType());
     $this->assertTrue($var->isTypeInferred());
 }
 public function testGetSlotFromFunctionScope()
 {
     $functionScope = new Scope($this->getMock('PHPParser_Node'));
     $functionScope->declareVar('x', $this->registry->getNativeType('integer'));
     $flowScope = LinkedFlowScope::createLatticeElement($functionScope);
     $this->assertNotNull($var = $flowScope->getSlot('x'));
     $this->assertSame($this->registry->getNativeType('integer'), $var->getType());
     $flowScope = $flowScope->createChildFlowScope();
     $this->assertNotNull($var = $flowScope->getSlot('x'));
     $this->assertSame($this->registry->getNativeType('integer'), $var->getType());
 }
 /**
  * Declares a variable.
  *
  * @param string $name
  * @param array $types
  * @param boolean $typesInferred
  */
 private function declareVar($name, PhpType $type = null, $typeInferred = true, \PHPParser_Node $nameNode = null)
 {
     if ($this->scope->isDeclared($name)) {
         return $this->scope->getVar($name);
     }
     $var = $this->scope->declareVar($name, $type, $typeInferred);
     if ($nameNode) {
         $var->setNameNode($nameNode);
     }
     return $var;
 }
 public function createScope(\PHPParser_Node $node, Scope $parent = null)
 {
     $thisType = $this->getThisType($node, $parent);
     // Constructing the global scope is very different than constructing inner scopes, because only global scopes
     // can contain named classes that show up in the type registry.
     $newScope = null;
     if (null === $parent) {
         $newScope = new Scope($node, null, $thisType);
         $builder = new GlobalScopeBuilder($newScope, $this->typeRegistry);
         NodeTraversal::traverseWithCallback($node, $builder);
     } else {
         $newScope = new Scope($node, $parent, $thisType);
         $builder = new LocalScopeBuilder($newScope, $this->typeRegistry);
         NodeTraversal::traverseWithCallback($node, $builder);
     }
     if (null !== $thisType) {
         $newScope->declareVar('this', $thisType);
     }
     return $newScope;
 }
 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);
     }
 }