public function isSubTypeOf(PhpType $that)
 {
     if ($that->isBooleanType()) {
         return true;
     }
     return parent::isSubTypeOf($that);
 }
 private function isSubtype(PhpType $a, PhpType $b)
 {
     if ($a->isUnknownType()) {
         return false;
     }
     if (null === ($objType = $a->toMaybeObjectType())) {
         return false;
     }
     return $objType->isSubtypeOf($b);
 }
 public function addAlternate(PhpType $alternate)
 {
     // build() returns the bottom type by default, so we can
     // just bail out early here.
     if ($alternate->isNoType()) {
         return $this;
     }
     $this->isAllType = $this->isAllType || $alternate->isAllType();
     $isAlternateUnknown = $alternate instanceof UnknownType;
     // instanceof is desired here
     $this->isNativeUnknownType = $this->isNativeUnknownType || $isAlternateUnknown;
     if ($isAlternateUnknown) {
         $this->areAllUnknownsChecked = $this->areAllUnknownsChecked && $alternate->isChecked();
     }
     if (!$this->isAllType && !$this->isNativeUnknownType) {
         if ($alternate->isUnionType()) {
             $union = $alternate->toMaybeUnionType();
             foreach ($union->getAlternates() as $unionAlt) {
                 $this->addAlternate($unionAlt);
             }
         } else {
             // Look through the alternates we've got so far,
             // and check if any of them are duplicates of
             // one another.
             foreach ($this->alternates as $index => $current) {
                 // The Unknown type is special in that we cannot use our
                 // subtype based check, but need to check for equality to
                 // avoid duplicates, and not remove all other alternates.
                 if ($alternate->isUnknownType()) {
                     if ($alternate->equals($current)) {
                         return $this;
                     }
                     continue;
                 }
                 // Check if we already have a more general type in the union.
                 // Then, we do not add this alternate.
                 if ($alternate->isSubTypeOf($current)) {
                     return $this;
                 }
                 // Check if we have a subtype of the passed alternate. Then,
                 // we remove that alternate in favor of the newly passed one.
                 if ($current->isSubTypeOf($alternate)) {
                     unset($this->alternates[$index]);
                 }
             }
             $this->alternates[] = $alternate;
         }
     }
     return $this;
 }
 public function getThisType(PhpType $objType)
 {
     switch (true) {
         case $objType instanceof ProxyObjectType:
             $className = $objType->getReferenceName();
             break;
         case $objType instanceof MethodContainer:
             $className = $objType->getName();
             break;
         default:
             throw new \LogicException(sprintf('The previous CASES were exhaustive. Unknown type "%s".', get_class($objType)));
     }
     $loweredClassName = strtolower($className);
     if (!isset($this->thisTypes[$loweredClassName])) {
         $this->thisTypes[$loweredClassName] = new ThisType($this, $this->getClassOrCreate($className));
     }
     return $this->thisTypes[$loweredClassName];
 }
 protected function getRestrictedByGetClassResult(PhpType $type = null, $value, $resultEqualsValue)
 {
     if (null === $type) {
         if ($resultEqualsValue) {
             return $this->typeRegistry->getClassOrCreate($value);
         }
         return null;
     }
     return $type->visit(new RestrictByGetClassResultVisitor($this->typeRegistry, $value, $resultEqualsValue));
 }
 /**
  * @dataProvider getEqualsTests
  */
 public function testEquals(PhpType $a, PhpType $b, $expectedOutcome)
 {
     $this->assertSame($expectedOutcome, $a->equals($b));
 }
 private function restrictByCallable(PhpType $type = null, $outcome)
 {
     if (null === $type) {
         return $outcome ? $this->typeRegistry->getNativeType('callable') : null;
     }
     if ($outcome) {
         if ($type->isUnknownType() || $type->isAllType()) {
             return $this->typeRegistry->getNativeType('callable');
         }
         if ($type->isUnionType()) {
             $types = array();
             foreach ($type->getAlternates() as $altType) {
                 if ($altType->canBeCalled()) {
                     $types[] = $altType;
                 }
             }
             return $this->typeRegistry->createUnionType($types);
         }
         return $type->canBeCalled() ? $type : $this->typeRegistry->getNativeType('none');
     }
     if ($type->isCallableType()) {
         return $this->typeRegistry->getNativeType('none');
     }
     if ($type->isUnionType()) {
         $types = array();
         foreach ($type->getAlternates() as $altType) {
             if ($altType->isCallableType()) {
                 continue;
             }
             $types[] = $altType;
         }
         return $this->typeRegistry->createUnionType($types);
     }
     return $type;
 }
 public function isSubtypeOf(PhpType $that)
 {
     if (PhpType::isSubTypeOf($that)) {
         return true;
     }
     if ($that->isNoObjectType()) {
         return true;
     }
     if ($that->isCallableType() && (!$this->isNormalized() || $this->hasMethod('__invoke'))) {
         return true;
     }
     if (false === $that->isObjectType()) {
         return false;
     }
     if (false === $this->isNormalized()) {
         return true;
     }
     if ($that->isInterface()) {
         $name = strtolower($that->toMaybeObjectType()->getName());
         foreach ($this->extendedInterfaces as $iName) {
             if ($name === strtolower($iName)) {
                 return true;
             }
         }
         return false;
     }
     if ($that instanceof ProxyObjectType) {
         $name = strtolower($that->getReferenceName());
         foreach ($this->extendedInterfaces as $iName) {
             if ($name === strtolower($iName)) {
                 return true;
             }
         }
         return false;
     }
     return false;
 }
 private function hasTypeChanged(PhpType $newType, PhpType $currentType = null)
 {
     if (null === $currentType) {
         return true;
     }
     return false === $newType->equals($currentType);
 }
示例#10
0
 /**
  * Returns whether the passed type is meaningfully different from this type.
  *
  * In contrast to ``equals()``, this method treats unknown types specially.
  *
  * If no unknown type is involved, then the result of this method is the opposite
  * boolean result of ``equals()``.
  *
  * If unknown types are involved, we regard the types as different if only one
  * of the involved types is an unknown type.
  *
  * TODO: Since the difference between known unknowns (aka checked unknowns),
  *       and unknown unknowns has been removed. This method should be superfluous.
  *
  * @see http://www.youtube.com/watch?v=QaxqUDd4fiw&feature=related
  */
 public function differsFrom(PhpType $that)
 {
     if (!$this->isUnknownType() && !$that->isUnknownType()) {
         return !$this->equals($that);
     }
     return (bool) ($this->isUnknownType() ^ $that->isUnknownType());
 }
 /**
  * Refines an array type with the information about the used key, and assigned element type.
  *
  * This also defines the type for the item key if available and non-dynamic.
  *
  * @param PhpType $varType
  * @param PhpType $resultType
  * @param \PHPParser_Node_Expr_ArrayDimFetch $node
  *
  * @return ArrayType
  */
 private function getRefinedArrayType(PhpType $varType, PhpType $resultType, \PHPParser_Node_Expr_ArrayDimFetch $node)
 {
     $usedKeyType = $this->getKeyTypeForDimFetch($node);
     $keyType = $varType->getKeyType();
     if ($keyType === $this->typeRegistry->getNativeType('generic_array_key')) {
         $refinedKeyType = $usedKeyType;
     } else {
         $refinedKeyType = $keyType->getLeastSupertype($usedKeyType);
     }
     $elementType = $varType->getElementType();
     if ($elementType === $this->typeRegistry->getNativeType('generic_array_value')) {
         $refinedElementType = $resultType;
     } else {
         $refinedElementType = $elementType->getLeastSupertype($resultType);
     }
     $refinedType = $this->typeRegistry->getArrayType($refinedElementType, $refinedKeyType);
     // Infer the type of the key if a concrete value is available.
     NodeUtil::getValue($node->dim)->map(function ($keyName) use(&$refinedType, $resultType) {
         $refinedType = $refinedType->inferItemType($keyName, $resultType);
     });
     return $refinedType;
 }
 private function getClassName(PhpType $type)
 {
     if ($type instanceof NamedType) {
         return $type->getReferenceName();
     }
     $methodContainer = $type->toMaybeObjectType();
     if ($methodContainer instanceof Clazz) {
         return $methodContainer->getName();
     }
     return null;
 }
示例#13
0
 public function equals(PhpType $type)
 {
     if ($type->isClass() && strtolower($type->toMaybeObjectType()->getName()) === strtolower($this->getName())) {
         return true;
     }
     if ($type instanceof ProxyObjectType && strtolower($type->getReferenceName()) === strtolower($this->getName())) {
         return true;
     }
     return false;
 }
 private function getStringRepr(PhpType $type)
 {
     switch (true) {
         case $type instanceof AllType:
             return TypeRegistry::NATIVE_ALL;
             // This handles the generic array type specially.
         // This handles the generic array type specially.
         case $type === self::$typeRegistry->getNativeType('array'):
             return 'array';
         case $type instanceof ArrayType:
             $itemTypes = $type->getItemTypes();
             if (empty($itemTypes)) {
                 return TypeRegistry::NATIVE_ARRAY . '<' . $this->getStringRepr($type->getKeyType()) . ',' . $this->getStringRepr($type->getElementType()) . '>';
             }
             return sprintf('array<%s,%s,%s>', $this->getStringRepr($type->getKeyType()), $this->getStringRepr($type->getElementType()), $this->dumpJsonLike($itemTypes, true));
         case $type instanceof FalseType:
             return TypeRegistry::NATIVE_BOOLEAN_FALSE;
         case $type instanceof BooleanType:
             return TypeRegistry::NATIVE_BOOLEAN;
         case $type instanceof CallableType:
             return TypeRegistry::NATIVE_CALLABLE;
         case $type instanceof ResourceType:
             return TypeRegistry::NATIVE_RESOURCE;
         case $type instanceof DoubleType:
             return TypeRegistry::NATIVE_DOUBLE;
         case $type instanceof IntegerType:
             return TypeRegistry::NATIVE_INTEGER;
         case $type instanceof ThisType:
             return 'this<' . $type->getReferenceName() . '>';
         case $type instanceof NamedType:
             // If this type has been resolved, we can get the representation
             // of the resolved type instead of using the reference name.
             if (!$type->isNoResolvedType()) {
                 return $this->getStringRepr($type->getReferencedType());
             }
             return 'object<' . $type->getReferenceName() . '>';
         case $type instanceof NoObjectType:
             return TypeRegistry::NATIVE_OBJECT;
         case $type instanceof NoType:
             return TypeRegistry::NATIVE_NONE;
         case $type instanceof NullType:
             return TypeRegistry::NATIVE_NULL;
         case $type instanceof ObjectType:
             return 'object<' . $type->getName() . '>';
         case $type instanceof StringType:
             return TypeRegistry::NATIVE_STRING;
         case $type instanceof UnionType:
             $alt = array();
             foreach ($type->getAlternates() as $t) {
                 $alt[] = $this->getStringRepr($t);
             }
             return implode('|', $alt);
         case $type instanceof UnknownType:
             return $type->isChecked() ? TypeRegistry::NATIVE_UNKNOWN_CHECKED : TypeRegistry::NATIVE_UNKNOWN;
     }
     throw new \InvalidArgumentException(sprintf('The SWITCH statement is exhaustive, but got "%s".', get_class($type)));
 }
 private function isNullableObjectType(PhpType $type)
 {
     if (!$type->isUnionType()) {
         return false;
     }
     foreach ($type->getAlternates() as $alt) {
         if (null === $alt->toMaybeObjectType() && !$alt->isNullType()) {
             return false;
         }
     }
     return true;
 }
 /**
  * Returns the array type contained in the given type, or null if no array
  * type is available.
  *
  * @param PhpType|null $type
  *
  * @return ArrayType|null
  */
 private function getContainedArrayType(PhpType $type = null)
 {
     if (null === $type) {
         return null;
     }
     if ($type->isArrayType()) {
         return $type;
     }
     if (!$type->isUnionType()) {
         return null;
     }
     foreach ($type->getAlternates() as $alt) {
         if ($alt->isArrayType()) {
             return $alt;
         }
     }
     return null;
 }
 private function isMoreSpecificType(PhpType $actualType, PhpType $annotatedType)
 {
     if ($actualType->equals($annotatedType)) {
         return false;
     }
     if ($actualType->isUnknownType()) {
         return false;
     }
     return $actualType->isSubtypeOf($annotatedType);
 }