/** * Return whether this type is a placeholder. Given a type name "T" or * "T[]", this method will return true if "T" is contained in this * types' components, e.g. as in "List<T>". * * @param xp.compiler.types.TypeName ref * @return bool */ public function isPlaceholder(self $ref) { if ($ref->isArray()) { $cmp = $ref->arrayComponentType(); } else { $cmp = $ref; } foreach ($this->components as $component) { if ($component->name === $cmp->name) { return true; } } return false; }
public function kAndVArePlaceHoldersInMapOfKV() { $decl = new TypeName('Map', [new TypeName('K'), new TypeName('V')]); $this->assertTrue($decl->isPlaceholder(new TypeName('K')), 'K'); $this->assertTrue($decl->isPlaceholder(new TypeName('V')), 'V'); }
/** * Resolve a type name * * @param xp.compiler.types.TypeName name * @param bool register * @return xp.compiler.types.Types resolved * @throws xp.compiler.types.ResolveException */ public function resolveType(TypeName $name, $register = true) { if ($name->isArray()) { return new ArrayTypeOf($this->resolveType($name->arrayComponentType(), $register)); } else { if ($name->isMap()) { return new MapTypeOf($this->resolveType($name->mapComponentType(), $register)); } else { if (!$name->isClass()) { return new PrimitiveTypeOf($name); } else { if ($name->isGeneric()) { return new GenericType($this->resolveType(new TypeName($name->name), $register), $name->components); } else { if ($name->isFunction()) { return new FunctionTypeOf($this->resolveType($name->functionReturnType(), $register), $name->components); } } } } } if ($this->declarations) { $decl = $this->declarations[0]; // Keywords: self, parent if ('self' === $name->name || $name->name === $decl->name->name) { return $this->resolved['self']; } else { if ('parent' === $name->name) { return $this->resolved['parent']; } } // See if this type is part of our generic type, return a place holder foreach ($decl->name->components as $component) { if ($component->equals($name)) { return new TypeReference($name, Types::UNKNOWN_KIND); } } // Fall through } $normalized = strtr($name->name, '\\', '.'); if ('xp' === $normalized) { return new TypeReference($name, Types::UNKNOWN_KIND); } else { if (0 === strncmp('php.', $normalized, 4)) { return new TypeReflection(new XPClass(substr($normalized, strrpos($normalized, '.') + 1))); } else { if (strpos($normalized, '.')) { $qualified = $normalized; } else { if (isset($this->imports[$normalized])) { $qualified = $this->imports[$normalized]; } else { $lookup = $this->package ? array_merge($this->packages, [$this->package->name]) : array_merge($this->packages, [null]); try { $qualified = $this->task->locateClass($lookup, $normalized); } catch (\lang\ElementNotFoundException $e) { throw new ResolveException('Cannot resolve ' . $name->toString(), 423, $e); } } } } } // Locate class. If the classloader already knows this class, // we can simply use this class. TODO: Use specialized // JitClassLoader? if (!$this->resolved->containsKey($qualified)) { if (class_exists(literal($qualified), false) || interface_exists(literal($qualified), false) || ClassLoader::getDefault()->providesClass($qualified)) { try { $this->resolved[$qualified] = new TypeReflection(XPClass::forName($qualified)); } catch (\lang\Throwable $e) { throw new ResolveException('Class loader error for ' . $name->toString() . ': ' . $e->getMessage(), 507, $e); } } else { try { $type = $this->task->newSubTask($qualified)->run($this); } catch (\xp\compiler\CompilationException $e) { throw new ResolveException('Cannot resolve ' . $name->toString(), 424, $e); } catch (\lang\Throwable $e) { throw new ResolveException('Cannot resolve ' . $name->toString(), 507, $e); } $this->resolved[$qualified] = $type; } } $register && ($this->used[$qualified] = true); return $this->resolved[$qualified]; }