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; }
/** * 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 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; }
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; }
/** * Computes the restricted types given a non-successful shallow equality comparison. * * @return PhpType[] The first element is the restricted this type, the second element is the restricted type of the * passed type. */ public function getTypesUnderShallowInequality(PhpType $that) { // union types if ($that->isUnionType()) { $p = $that->toMaybeUnionType()->getTypesUnderShallowInequality($this); return array($p[1], $p[0]); } // Other types. // There are only two types whose shallow inequality is deterministically // true -- null and false. We can just enumerate them. Should we ever add // a true type, this needs to be added here as well. if ($this->isNullType() && $that->isNullType()) { return array(null, null); } if ($this->isFalse() && $that->isFalse()) { return array(null, null); } return array($this, $that); }