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;
 }
 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;
 }
 /**
  * @param string $type
  *
  * @return null|PhpType
  */
 private function tryGettingMoreSpecificType(PhpType $docType = null, PhpType $actualType, AbstractFunction $function, array $importedNamespaces, MethodContainer $container = null, $type)
 {
     if (!$docType) {
         if (!$actualType->isUnknownType() && !$actualType->isAllType()) {
             return null;
         }
         return $this->{'infer' . $type . 'TypeForFunction'}($function, $container);
     }
     // If the type defined by the comment is an object (and not the NoObjectType),
     // and a super type of the actual type, we keep it.
     if (null !== $docType->toMaybeObjectType() && $actualType->isSubtypeOf($docType)) {
         return $docType;
     }
     // If the type defined by the comment is a nullable object type (excluding the
     // NoObject type), we keep the comment that is currently in place.
     if ($this->isNullableObjectType($docType) && $actualType->isSubtypeOf($docType)) {
         return $docType;
     }
     if ($docType->getDocType($importedNamespaces) !== $actualType->getDocType($importedNamespaces)) {
         return $actualType;
     }
     if ($actualType === $this->registry->getNativeType('array')) {
         $inferredType = $this->{'infer' . $type . 'TypeForFunction'}($function, $container);
         if ($inferredType && $inferredType->isArrayType()) {
             return $inferredType;
         }
     }
     return null;
 }
Exemplo n.º 5
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());
 }
 private function isMoreSpecificType(PhpType $actualType, PhpType $annotatedType)
 {
     if ($actualType->equals($annotatedType)) {
         return false;
     }
     if ($actualType->isUnknownType()) {
         return false;
     }
     return $actualType->isSubtypeOf($annotatedType);
 }