Example #1
0
 /**
  * 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;
 }
Example #2
0
 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');
 }
Example #3
0
 /**
  * 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];
 }