public function visitConditional(Node $node) : UnionType { $union_type = new UnionType(); // Add the type for the 'true' side $union_type->addUnionType(UnionType::fromNode($this->context, $this->code_base, $node->children['trueExpr'] ?? $node->children['true'] ?? '')); // Add the type for the 'false' side $union_type->addUnionType(UnionType::fromNode($this->context, $this->code_base, $node->children['falseExpr'] ?? $node->children['false'] ?? '')); return $union_type; }
/** * @param CodeBase * The code base to use in order to find super classes, etc. * * @param $recursion_depth * This thing has a tendency to run-away on me. This tracks * how bad I messed up by seeing how far the expanded types * go * * @return UnionType * Expands class types to all inherited classes returning * a superset of this type. */ public function asExpandedTypes(CodeBase $code_base, int $recursion_depth = 0) : UnionType { return $this->memoize(__METHOD__, function () use($code_base, $recursion_depth) : UnionType { // We're going to assume that if the type hierarchy // is taller than some value we probably messed up // and should bail out. assert($recursion_depth < 20, "Recursion has gotten out of hand for type {$this}"); if ($this->isNativeType()) { return $this->asUnionType(); } $union_type = $this->asUnionType(); $class_fqsen = $this->isGenericArray() ? $this->genericArrayElementType()->asFQSEN() : $this->asFQSEN(); if (!$code_base->hasClassWithFQSEN($class_fqsen)) { return $union_type; } $clazz = $code_base->getClassByFQSEN($class_fqsen); $union_type->addUnionType($this->isGenericArray() ? $clazz->getUnionType()->asGenericArrayTypes() : $clazz->getUnionType()); // Resurse up the tree to include all types $recursive_union_type = new UnionType(); foreach ($union_type->getTypeSet() as $clazz_type) { if ((string) $clazz_type != (string) $this) { $recursive_union_type->addUnionType($clazz_type->asExpandedTypes($code_base, $recursion_depth + 1)); } else { $recursive_union_type->addType($clazz_type); } } return $recursive_union_type; }); }
/** * Visit a node with kind `\ast\AST_CONDITIONAL` * * @param Node $node * A node of the type indicated by the method name that we'd * like to figure out the type that it produces. * * @return UnionType * The set of types that are possibly produced by the * given node */ public function visitConditional(Node $node) : UnionType { $true_type = UnionType::fromNode($this->context, $this->code_base, $node->children['trueExpr'] ?? $node->children['true'] ?? ''); $false_type = UnionType::fromNode($this->context, $this->code_base, $node->children['falseExpr'] ?? $node->children['false'] ?? ''); $union_type = new UnionType(); // Add the type for the 'true' side $union_type->addUnionType($true_type); // Add the type for the 'false' side $union_type->addUnionType($false_type); // If one side has an unknown type but the other doesn't // we can't let the unseen type get erased. Unfortunately, // we need to add 'mixed' in so that we know it could be // anything at all. // // See Issue #104 if ($true_type->isEmpty() xor $false_type->isEmpty()) { $union_type->addUnionType(MixedType::instance()->asUnionType()); } return $union_type; }
/** * @param CodeBase * The code base to use in order to find super classes, etc. * * @param $recursion_depth * This thing has a tendency to run-away on me. This tracks * how bad I messed up by seeing how far the expanded types * go * * @return UnionType * Expands class types to all inherited classes returning * a superset of this type. */ public function asExpandedTypes(CodeBase $code_base, int $recursion_depth = 0) : UnionType { return $this->memoize(__METHOD__, function () use($code_base, $recursion_depth) : UnionType { assert($recursion_depth < 10, "Recursion has gotten out of hand for type {$this}"); if ($this->isNativeType()) { return $this->asUnionType(); } $union_type = $this->asUnionType(); $class_fqsen = $this->isGenericArray() ? $this->genericArrayElementType()->asFQSEN() : $this->asFQSEN(); if (!$code_base->hasClassWithFQSEN($class_fqsen)) { return $union_type; } $clazz = $code_base->getClassByFQSEN($class_fqsen); $union_type->addUnionType($this->isGenericArray() ? $clazz->getUnionType()->asGenericArrayTypes() : $clazz->getUnionType()); // Resurse up the tree to include all types $recursive_union_type = new UnionType(); foreach ($union_type->getTypeList() as $clazz_type) { if ((string) $clazz_type != (string) $this) { $recursive_union_type->addUnionType($clazz_type->asExpandedTypes($code_base, $recursion_depth + 1)); } else { $recursive_union_type->addType($clazz_type); } } return $recursive_union_type; }); }
/** * @param CodeBase * The code base to use in order to find super classes, etc. * * @param $recursion_depth * This thing has a tendency to run-away on me. This tracks * how bad I messed up by seeing how far the expanded types * go * * @return UnionType * Expands all class types to all inherited classes returning * a superset of this type. */ public function asExpandedTypes(CodeBase $code_base, int $recursion_depth = 0) : UnionType { assert($recursion_depth < 10, "Recursion has gotten out of hand for type {$this}"); $union_type = new UnionType(); foreach ($this->type_set as $type) { $union_type->addUnionType($type->asExpandedTypes($code_base, $recursion_depth + 1)); } return $union_type; }